1 ELISA STANDARDIZATION

1.1 Aim

  • Principal:
    • Implement a reproducible standardization of OD values across ELISA plates following Miura et.al., 20081.
  • Secondary:
    • Generate useful outputs to compare standardization quality.

1.2 To Do

  • Write methods for the manuscript.

1.3 Dependencies

The required R packages for this analysis are:

  • plater2
  • readxl3
  • tidyxl4
  • drc5
##essential
library(tidyverse)    # set of tidy packages (readr, tibble, dplyr, tidyr, ggplot2, ¿purr?)
library(tidyxl)       # read untidy excel formats
library(readxl)       # read excel files as tidy tables
library(drc)          # fit dose-response models
library(mixtools)     # analyze finete mixture models
##accesory
library(DiagrammeR)   # create flowchart
theme_set(theme_bw())

1.4 Method

  • using DiagrammeR6
#install.packages("DiagrammeR")
#library(DiagrammeR)
DiagrammeR("
  graph LR
    A[XLS data] -.-> |readxl+tidyxl| B{R data}
    Z[CSV data] -.-> |plater| B{R data}
    B --> C1[STD]
    B --> E[ctr +/-]
    B --> D1[UNK]
    
    C1 -.-> |drc| C2[4pLL model]
    C2 --> C3[Box-Cox]
    C3 --> F{UNK Ab.units}
    D1 --> D2[mean.OD]
    D2 --> D3[OD %CV]
    D3 --> F
    
    F --> G1[Histogram]
    F --> G2[Density]
    F --> G3[QQPlot]
    style Z fill:#ffffff, stroke:#000000, stroke-width:2px    
    style A fill:#ffffff, stroke:#000000, stroke-width:2px
    style B fill:#ffffff, stroke:#000000, stroke-width:2px
    style C1 fill:#ffffff, stroke:#000000, stroke-width:2px
    style C2 fill:#ffffff, stroke:#000000, stroke-width:2px
    style C3 fill:#ffffff, stroke:#000000, stroke-width:2px
    style D1 fill:#ffffff, stroke:#000000, stroke-width:2px
    style D2 fill:#ffffff, stroke:#000000, stroke-width:2px
    style D3 fill:#ffffff, stroke:#000000, stroke-width:2px
    style E fill:#ffffff, stroke:#000000, stroke-width:2px
    style F fill:#ffffff, stroke:#000000, stroke-width:2px
    style G1 fill:#ffffff, stroke:#000000, stroke-width:2px
    style G2 fill:#ffffff, stroke:#000000, stroke-width:2px
    style G3 fill:#ffffff, stroke:#000000, stroke-width:2px
")

1.4.1 Log-Logistic (4pLL) model

The curve of the log-logistic symetric model describe the response f(x) dependent of the dose x and 04 parameters: \[ f(x)=f(x;b,c,d,e)=c+\frac{d-c}{1+\exp[b(log(x)-log(e))]}\ \] where:

  • c is the lower limit of the response when the dose x approaches infinity,
  • d is the upper limit when the dose x approaches zero,
  • b is the slope around the point of inflection, represented by
  • e defined as effective dose and commmonly denoted as5:
    • ED50, EC50 or IC50 for continuous responses,
    • LD50 or LC50 for binomial responses, and
    • \(T_{50}\) for event-time responses.

1.5 Procedure

12 summary plots per ELISA Template:

  • 3x3 plots of STD and UNK distribution, residual variance distribution, and model transformation.
  • 1x3 plots of OD450nm, mean.OD and Ab.units distributions by Density plots.
getwd()
[1] "/home/avallec/Documents/Valle_GnB/0projects/R_/elixr"

1.5.1 phenotypes

#x <- tidyxl::tidy_xlsx("data-raw/raw/unap-tesis/RAFAEL-data/TEMPLATES Rafael.xlsx")$data$`TEMPLATE ELISA N°1`
x <- tidyxl::tidy_xlsx("data-raw/raw/unap-tesis/RAFAEL-data/TEMPLATES Rafael.xlsx")$data
#str(x)
y <- x[[3]] %>% #i
  filter(row %in% 23:29,
         col %in% 2:13) %>% 
  dplyr::select(address,row,col,numeric,character,local_format_id) %>% 
  unite(ID,c("numeric","character")) %>% 
  mutate(ID= stringr::str_replace(ID,"_NA|NA_", ""),
         Plate= paste0("N",3)) %>% #i
  dplyr::select(Plate,everything()) %>% 
  filter(!ID %in% c("C+","C-","NA","Blank")) #%>% group_by(ID) %>% slice(1) %>% ungroup()
y <- y[FALSE,]
#str(y)
for(i in 1:length(x)){
  
  a <- x[[i]] %>% #i
  filter(row %in% 23:29,
         col %in% 2:13) %>% 
  dplyr::select(address,row,col,numeric,character,local_format_id) %>% 
  unite(ID,c("numeric","character")) %>% 
  mutate(ID= stringr::str_replace(ID,"_NA|NA_", ""),
         Plate= paste0("N",i)) %>% #i
  dplyr::select(Plate,everything()) %>% 
  filter(!ID %in% c("C+","C-","NA","Blank")) #%>% group_by(ID) %>% slice(1) %>% ungroup()
  
  y <- union(y,a)
  
}
y <- y %>% arrange(Plate,row,col)
#y %>% dplyr::count(Plate)
#std.raw
y <- y %>%
  #dplyr::count(ID) %>% dplyr::arrange(desc(n))
  #filter(ID==2235)
  #filter(ID==1856)
  #filter(ID==3942)
  mutate(pheno=ifelse(local_format_id %in% c(23,17,20,18,21,19,22),"asymptomatic",
                      ifelse(local_format_id %in% c(68,69,70,71,72,73,24),"symptomatic",
                             NA_character_)
                      )
         ) #%>% 
  #filter(ID==2235)
  #filter(pheno=="asymptomatic") #%>% dplyr::select(ID)
  #mutate(pheno=ifelse(ID %in% . %>% filter(pheno=="asymptomatic") %>% dplyr::select(ID),"asym","sym"))
w <- y %>% filter(pheno=="asymptomatic") %>% dplyr::select(ID)
phe <- y %>% 
  mutate(pheno= ifelse(ID %in% w$ID,"asymptomatic","symptomatic")) %>% # RESPETA pheno de PLACA 1 y 2 !
  mutate(igg=ifelse(local_format_id %in% c(85),"igg1",
                    ifelse(local_format_id %in% c(87),"igg2",
                           ifelse(local_format_id %in% c(88,25),"igg3",
                                  ifelse(local_format_id %in% c(90),"igg4",
                                         "igg")
                                  )
                           )
                    )
         ) %>% #group_by(ID,igg) %>% slice(1) %>% ungroup() %>% 
  dplyr::select(-local_format_id#,-address,-row,-col
         ) %>% 
  arrange(Plate,row,col) %>% 
  mutate(Plate= as.factor(Plate)) %>% 
  dplyr::select(-address,-starts_with("row"),-col#,-loc
         ) %>% 
  mutate(pheno=ifelse(Plate=="N2" | 
                        Plate=="N6" | 
                        Plate=="N7",
                      "symptomatic",pheno)) # RESPETAR pheno POR PLACA (OJO: más de un pheno por paciente)
  
#filter(ID=="3053") # asympt in template 6 y 7
  #dplyr::count(pheno,igg)
  #dplyr::count(igg)
  
#phe# %>% dplyr::count(Plate)
#phe %>% group_by(Plate) %>% slice(1)
#phe %>% dplyr::count(Plate,pheno,igg) %>% arrange(Plate)

1.5.2 data

wb_sheet <- readxl::excel_sheets("data-raw/raw/unap-tesis/RAFAEL-data/TEMPLATES Rafael.xlsx")
all <- data_frame(ID=as.character(),
                  OD=as.double(),
                  Plate=as.character(),
                  Type=as.character(),
                  Ab.unit=as.double(),
                  order=as.integer()
                  )
#str(all)
# 2 GENERATE R DATA.FRAME
for (j in 1:length(wb_sheet)) {
  
  wb_Pf_main <- readxl::read_xlsx("data-raw/raw/unap-tesis/RAFAEL-data/TEMPLATES Rafael.xlsx",
                  range = "A21:M29",
                  sheet = j)#j
  wb_Pf <- readxl::read_xlsx("data-raw/raw/unap-tesis/RAFAEL-data/TEMPLATES Rafael.xlsx",
                  range = "A35:M43",
                  sheet = j)#j
  
  all_p <- wb_Pf_main %>% 
  dplyr::rename(row="X__1") %>% 
  gather(loc,ID,-row) %>% 
  mutate(loc=as.numeric(loc)) %>% 
  arrange(row,loc) %>% 
  mutate(ID= ifelse(row == "H" & loc == 9, "Blank", ID)) %>% #ANOTACION AUSCENTE EN TEMPLATES
  full_join(
    wb_Pf %>% 
      dplyr::rename(row="X__1") %>% 
      gather(loc,OD,-row) %>% 
      mutate(loc=as.numeric(loc)) %>% 
      arrange(row,loc)
  ) %>% 
  mutate(Plate=paste0("N",j),#j
         Type=ifelse(row=="A" | ID=="Blank","std",
                     ifelse(ID=="C+" | ID=="C-","ctr","unk")),
         Ab.unit=ifelse(row=="A",stringr::str_replace(ID,"STD 1/(.+)","\\1"),
                    ifelse(ID=="Blank","0",NA_character_))
         ) %>% 
  mutate(Ab.unit=as.numeric(Ab.unit)) %>% 
  mutate(Ab.unit=ifelse(row=="A",max(Ab.unit,na.rm=T)/Ab.unit,Ab.unit)) %>% #select(-row,-loc)
  replace_na(list(ID = "na")) %>% 
  filter(ID!="na") %>% 
  mutate(order=seq(1,dim(.)[1])) %>% 
  dplyr::select(#-address,
         -starts_with("row"),#-col,
         -loc)
  
  all <- union(all,all_p)
  
}
all <- all %>% arrange(Plate,order)
#all %>% dplyr::count(Type)
fin <- data_frame(Plate=as.character(),
                  order=as.integer(),
                  ID=as.character(),
                  Type=as.character(),
                  Ab.unit=as.double(),
                  OD=as.double(),
                  pheno=as.character(),
                  igg=as.character()
                  )
#str(fin)
for (j in 1:length(wb_sheet)) {
  
  fin_p <- full_join(phe %>% 
            filter(Plate==levels(phe$Plate)[j]) %>% #requires j
            mutate(order=seq(13,12+dim(.)[1])),
          all %>% 
            filter(Plate==levels(phe$Plate)[j]) %>% #requires j
            filter(Type=="unk") %>% 
            dplyr::select(-Plate,-ID),
          by="order") %>% 
    dplyr::select(Plate,order,ID,Type,Ab.unit,OD,pheno,igg)
  
  fin <- union(fin,fin_p)
  
}
fin <- fin %>% arrange(Plate,order)
#fin #%>% filter(ID==3053)
#OJO!!!! MALA ANOTACIÓN
#fin %>% filter(Plate=="N2") %>% dplyr::count(pheno)
#fin %>% filter(Plate=="N2") %>% filter(pheno=="asymptomatic")
#fin %>% dplyr::count(Plate)
end <- fin %>% 
  union(all %>% 
          filter(Type!="unk") %>% 
          dplyr::select(Plate,ID,Type,Ab.unit,OD,order) %>% 
          mutate(pheno=NA_character_,
                 igg=NA_character_)
        ) %>% 
  arrange(Plate,order) %>% 
  dplyr::select(-order)
#end #%>% filter(ID==2235)

1.5.3 standarization

# mod is mean  od (plus sd and cv)
mod <- end %>% 
  filter(Type=="unk") %>% 
  group_by(Plate,igg,ID) %>% 
  summarise_at(vars(OD),c("mean","sd")) %>% 
  ungroup() %>% 
  dplyr::rename(mean.OD="mean",
                sd.OD="sd") %>% 
  mutate(cv.OD=100*sd.OD/mean.OD) %>% 
  mutate(order=seq(1,dim(.)[1]))
  #filter(ID=="1570")
mab <- end %>% 
  filter(Type=="unk") %>% 
  group_by(Plate,igg,ID) %>% 
  slice(1) %>% 
  ungroup() %>% #filter(ID=="1570")
  mutate(order=seq(1,dim(.)[1])) %>% 
  full_join(mod %>% dplyr::select(order,mean.OD,sd.OD,cv.OD),
            by="order") %>% #mutate(test.id= ID.x==ID.y) %>% dplyr::count(test.id)
  dplyr::select(-order,-OD) %>% 
  mutate(ord=seq(1,dim(.)[1])) %>% 
  unite(code,ID,ord,sep="_",remove = F)

1.5.3.1 blank issue

#mascara
blk <- end %>% 
  filter(ID=="Blank") %>% 
  group_by(Plate) %>% slice(1) %>% ungroup() %>% 
  dplyr::select(-OD)
#media por par de blancos por placa
std <- end %>% 
  filter(ID=="Blank") %>% 
  group_by(Plate) %>% 
  summarise_at(vars(OD),mean,na.rm=T) %>% 
  ungroup() %>% 
  #dplyr::rename(mean.OD="OD") %>% 
  full_join(blk,by="Plate") %>% 
  dplyr::select(Plate,ID,Type,Ab.unit,OD,everything()) %>% 
  union(end %>% filter(Type=="std" & ID!="Blank")) %>% 
  arrange(Plate,Ab.unit) %>% 
  mutate(Plate=as.factor(Plate))

1.5.3.2 4pll per template

mab_ir <- NULL
mod_bx <- NULL
#
# new dose levels as support for the line
#mdo$Ab.units %>% summary()
new_x <- expand.grid(exp(seq(log(0.1),log(2048),length=100)))
# db to add predictions of all plates
new <- data_frame(ord=as.character(),
                  resp=as.double(),
                  p=as.double(),
                  pmin=as.double(),
                  pmax=as.double(),
                  Plate=as.character())
#
for (j in 1:length(levels(phe$Plate))) {
  
#
# 5 PARAMETER ESTIMATION 4pLL model
#
wb.m1 <- drm(OD ~ Ab.unit, Plate, 
               data= std %>% filter(Plate==levels(phe$Plate)[j]),#j
             #data= std,
               fct = LL.4(names = c("b", "c", "d", "e")))
#
wb.model <- wb.m1
# 6 BOX-COX TRANSFORMATION against RESIDUAL heterogeneity
wb.model.BX <- boxcox(wb.model, 
                     main=expression("Optimal " ~ lambda ~ " with confidence intervals"), 
                     plotit = FALSE)
#coefficients(wb.model.BX) %>% matrix(7,4)
mab_p <- mab %>% as.data.frame()
# 7 UNK AB.UNITS ESTIMATION by INVERSE REGRESSION
mir <- ED(wb.model.BX, 
                 mab_p[mab_p$Plate==levels(phe$Plate)[j],"mean.OD"],#j
                   #wb_MEAN[1:n,5],
                   type = "absolute",interval = "delta",
                   #clevel = "Pfal", 
                 display = FALSE)
  
mab_ir <- rbind(mab_ir,mir)
mod_bx <- rbind(mod_bx,coefficients(wb.model.BX))
#
# predictions and confidence intervals
pdm <- predict(wb.model.BX, newdata = new_x, interval = "confidence")
# new data with predictions
new_p <- bind_cols(new_x %>% 
                     as.tibble() %>% 
                     rownames_to_column(var = "ord")
                   , pdm %>% 
                     as.tibble() %>% 
                     rownames_to_column(var = "ord")
                   ) %>%
  dplyr::select(-ord1) %>% 
  mutate(Plate=levels(phe$Plate)[j]) %>% 
  dplyr::rename(resp=Var1,p=Prediction,pmin=Lower,pmax=Upper)
new <- union(new,new_p)
#
}
Error in optim(startVec, opfct, hessian = TRUE, method = optMethod, control = list(maxit = maxIt,  : 
  non-finite finite-difference value [2]
Error in optim(startVec, opfct, hessian = TRUE, method = optMethod, control = list(maxit = maxIt,  : 
  non-finite finite-difference value [2]
Error in optim(startVec, opfct, hessian = TRUE, method = optMethod, control = list(maxit = maxIt,  : 
  non-finite finite-difference value [2]
Error in optim(startVec, opfct, hessian = TRUE, method = optMethod, control = list(maxit = maxIt,  : 
  non-finite finite-difference value [2]
Error in optim(startVec, opfct, hessian = TRUE, method = optMethod, control = list(maxit = maxIt,  : 
  non-finite finite-difference value [2]
Error in optim(startVec, opfct, hessian = TRUE, method = optMethod, control = list(maxit = maxIt,  : 
  non-finite finite-difference value [2]
#mab
#mab[mab$Plate==levels(phe$Plate)[1],] #%>% duplicated() %>% sum()
# 7.1 FEED UNK AB.UNITS DATA.FRAME
mdo <- mab_ir %>% as.data.frame() %>% rownames_to_column() %>% 
  #dplyr::rename(ord=rowname) %>% 
  separate(rowname,c("par","Plate","mean.OD.c"),sep = ":") %>% 
  rownames_to_column("ord") %>% 
  #mutate(ord=seq(1,dim(.)[1])) %>% 
  full_join(mab %>% 
              mutate(ord=as.character(ord)) %>% 
              mutate(mean.OD.c=as.character(mean.OD))
            ,
            by = c("ord","Plate","mean.OD.c")) %>% 
  dplyr::select(Plate,ord,ID,code,Type,pheno,igg,mean.OD,sd.OD,cv.OD,Ab.units=Estimate,
         everything(),-par,-mean.OD.c,-Ab.unit) %>% 
  filter(!code=="2235_137") # MANUAL FILTERING of replicate on different templates
mod_bt <- mod_bx %>% as.data.frame() %>% rownames_to_column() %>% as.tibble() %>% 
  dplyr::rename(Plate=rowname) %>% 
  mutate(Plate=stringr::str_replace(Plate,"(\\d)","N\\1"))
new <- new %>% mutate(ord=as.numeric(ord)) %>% arrange(Plate,ord)

1.5.3.3 outputs

#
#fin
#end
#mod
#mab
# standard curve data
std
# estimated ab unit data
mdo
# estimated parameters per standard curve
mod_bt
# predicted model per standard curve 
new

1.5.4 quality control plots

#std
ctr <- end %>% filter(Type=="ctr")
#ctr %>% filter(Plate==levels(phe$Plate)[1] & ID=="C+") %>% .$OD
#std %>% filter(Plate==levels(phe$Plate)[1] & ID=="Blank") %>% .$OD

1.5.4.1 cv

mdo %>% 
  ggplot(aes(mean.OD,cv.OD,colour=Plate)) +
  geom_point() +
  coord_cartesian(ylim = c(0,100)) +
  geom_hline(aes(yintercept=20),linetype="dashed",size=0.3) +
  geom_vline(aes(xintercept=0.25),linetype="dashed",size=0.3) +
  facet_wrap(~Plate,ncol = 4) +
  labs(title="QC plot: Intra-plate coefficient of variation")

1.5.4.2 4pll

std %>% 
  mutate(Ab.unit=ifelse(Ab.unit==0,0.5,Ab.unit)) %>% 
  ggplot(aes(Ab.unit,OD)) +
  geom_hline(aes(yintercept=OD,linetype=ID),data=ctr) +
  geom_point(aes(colour=Plate)) +
  geom_ribbon(data=new, aes(x=resp, y=p, ymin=pmin, ymax=pmax), alpha=0.2) +
  geom_line(data=new, aes(x=resp, y=p, colour=Plate)) +
  #coord_trans(x="log") +
  scale_x_log10() +
  #theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  facet_wrap(~Plate,ncol = 4) +
  labs(title="QC plot: 4-parameter log-logistic model per plate")

  #xlab("Ferulic acid (mM)") + ylab("Root length (cm)")
std %>% 
  ggplot(aes(Ab.unit,OD,colour=Plate)) +
  geom_point() +
  facet_wrap(~Plate)
std %>% 
  ggplot(aes(log10(Ab.unit),OD,colour=Plate)) +
  geom_hline(aes(yintercept=OD,linetype=ID),ctr,size=0.3) +
  geom_point() +
  facet_wrap(~Plate)
mdo %>% 
  ggplot(aes(Ab.units,mean.OD,colour=igg)) +
  coord_cartesian(ylim = c(0,1)) +
  geom_point() +
  geom_errorbarh(aes(xmin=Lower,xmax=Upper), colour="black", size=.2) +
  scale_x_log10() +
  facet_wrap(~Plate+pheno,nrow = 2) + 
  labs(title="Estimates of antibody units (AU) per plate and phenotype")

  # inverse regression method
  #facet_wrap(igg~pheno,nrow = 2)

1.5.5 distribution plots

1.5.5.1 linear

1.5.5.1.1 scale fix
##### ab units
a <- mdo %>% 
  ggplot(aes(x=Ab.units,fill=pheno)) + theme_bw() #+
  #scale_x_log10()
b <- a +
  geom_histogram(alpha=.5,position = "identity") + facet_grid(~igg)
#ggsave("data-raw/raw/unap-tesis/RAFAEL-data/ab_hist.png")
c <- a + 
  geom_density(alpha=.5,position = "identity") + facet_grid(~igg)
#ggsave("data-raw/raw/unap-tesis/RAFAEL-data/ab_dens.png")
  #facet_wrap(transform~measure,scales = "free")
Rmisc::multiplot(b,c,cols = 1)

1.5.5.1.2 scale free
##### ab units
a <- mdo %>% 
  ggplot(aes(x=Ab.units,fill=pheno)) + theme_bw() #+
  #scale_x_log10()
b <- a +
  geom_histogram(alpha=.5,position = "identity") + 
  facet_wrap(~igg, scale= "free", ncol = 5)
#ggsave("data-raw/raw/unap-tesis/RAFAEL-data/ab_hist.png")
c <- a + 
  geom_density(alpha=.5,position = "identity") + 
  facet_wrap(~igg, scale= "free", ncol = 5)
#ggsave("data-raw/raw/unap-tesis/RAFAEL-data/ab_dens.png")
  #facet_wrap(transform~measure,scales = "free")
Rmisc::multiplot(b,c,cols = 1)

##### od
a <- mdo %>% 
  ggplot(aes(x=mean.OD,fill=pheno)) + theme_bw() #+
  #scale_x_log10()

b <- a +
  geom_histogram(alpha=.5,position = "identity") + facet_grid(~igg)
#ggsave("data-raw/raw/unap-tesis/RAFAEL-data/od_hist.png")

c <- a + 
  geom_density(alpha=.5,position = "identity") + facet_grid(~igg)
#ggsave("data-raw/raw/unap-tesis/RAFAEL-data/od_dens.png")
  #facet_wrap(transform~measure,scales = "free")

Rmisc::multiplot(b,c,cols = 1)

1.5.5.2 log

1.5.5.2.1 scale fix
##### ab units
a <- mdo %>% 
  ggplot(aes(x=Ab.units,fill=pheno)) + theme_bw() +
  scale_x_log10()
b <- a +
  geom_histogram(alpha=.5,position = "identity") + facet_grid(~igg)
#ggsave("data-raw/raw/unap-tesis/RAFAEL-data/ab_hist.png")
c <- a + 
  geom_density(alpha=.5,position = "identity") + facet_grid(~igg)
#ggsave("data-raw/raw/unap-tesis/RAFAEL-data/ab_dens.png")
  #facet_wrap(transform~measure,scales = "free")
Rmisc::multiplot(b,c,cols = 1)

1.5.5.2.2 scale free
##### ab units
a <- mdo %>% 
  ggplot(aes(x=Ab.units,fill=pheno)) + theme_bw() +
  scale_x_log10()
b <- a +
  geom_histogram(alpha=.5,position = "identity") + 
  facet_wrap(~igg, scale= "free", ncol = 5)
#ggsave("data-raw/raw/unap-tesis/RAFAEL-data/ab_hist.png")
c <- a + 
  geom_density(alpha=.5,position = "identity") + 
  facet_wrap(~igg, scale= "free", ncol = 5)
#ggsave("data-raw/raw/unap-tesis/RAFAEL-data/ab_dens.png")
  #facet_wrap(transform~measure,scales = "free")
Rmisc::multiplot(b,c,cols = 1)

##### od
a <- mdo %>% 
  ggplot(aes(x=mean.OD,fill=pheno)) + theme_bw() +
  scale_x_log10()

b <- a +
  geom_histogram(alpha=.5,position = "identity") + facet_grid(~igg)
#ggsave("data-raw/raw/unap-tesis/RAFAEL-data/od_hist.png")

c <- a + 
  geom_density(alpha=.5,position = "identity") + facet_grid(~igg)
#ggsave("data-raw/raw/unap-tesis/RAFAEL-data/od_dens.png")
  #facet_wrap(transform~measure,scales = "free")

Rmisc::multiplot(b,c,cols = 1)

2 COVARIATES

cova <- readxl::read_xlsx("data-raw/raw/unap-tesis/RAFAEL-data/Base Rafael.xlsx",
                  range = "A1:P59",
                  sheet = 1) %>% 
  slice(-1) %>% 
  dplyr::rename(EDAD="X__1",SEXO="X__2") %>% 
  rename_all(funs(stringr::str_to_lower(.))) %>% 
  dplyr::select(codigo:gametocitos) %>% 
  dplyr::select(codigo,condicion="condición",edad,sexo,comunidad,fiebre)
covb <- readxl::read_xlsx("data-raw/raw/unap-tesis/RAFAEL-data/DENSIDADES.xlsx",
                  range = "A1:E59",
                  sheet = 1) %>% 
  slice(-1) %>% 
  rename_all(funs(stringr::str_to_lower(.))) %>% 
  dplyr::select(1:4) %>% 
  dplyr::rename(par="parástios/ul de sangre") %>% 
  dplyr::select(-4) %>% 
  dplyr::rename(condicion="condición")

2.0.0.1 merge issues

  • 4 muestras con incompatibilidad de covariables en edad y sexo.
    • prioridad: parasitemia
    • retiro de observaciones con par=0
  • ¿variable condición?

  • SOLVE THIS!! AFFECTS HERE

covx <- full_join(cova, covb, by="codigo") 
covx %>% 
  dplyr::count(codigo) %>% arrange(desc(n)) %>% filter(n!=1)
#covx %>% filter(codigo=="2235" | codigo=="3053" | codigo=="9165" | codigo=="9801") %>% arrange(codigo) %>% 
#  dplyr::select(codigo,edad,sexo,par)
cova %>% filter(codigo=="2235" | codigo=="3053" | codigo=="9165" | codigo=="9801") %>% arrange(codigo) %>% 
  dplyr::select(codigo,edad,sexo)
covb %>% filter(codigo=="2235" | codigo=="3053" | codigo=="9165" | codigo=="9801") %>% arrange(codigo) %>% 
  dplyr::select(codigo,par)
# par covariates finale
covf <- covb %>% filter(!(codigo=="2235" & par==0 | codigo=="3053" & par==0 | codigo=="9165" & par==0 | codigo=="9801" & par==0)) %>% 
  dplyr::rename(ID=codigo)
mdo %>% dplyr::count(ID)
mco <- full_join(mdo,covf,by="ID") %>% #dplyr::count(pheno,condicion)
  dplyr::select(-condicion) %>% 
  mutate(Ab.units_log=log10(Ab.units))

2.0.0.2 test covariates

mcv <- covx %>% 
  #filter(codigo=="2235" | codigo=="3053" | codigo=="9165" | codigo=="9801") %>% 
  filter(!(codigo=="2235" | 
             codigo=="3053" | 
             codigo=="9165" | 
             codigo=="9801")) %>% 
  #filter(codigo=="2235" | codigo=="3053" | codigo=="9165" | codigo=="9801") %>% 
  arrange(codigo) %>% 
  dplyr::select(codigo,edad,sexo,par) %>% 
  dplyr::rename(ID=codigo) %>% 
  full_join(mdo %>% 
              group_by(ID) %>% 
              slice(1) %>% 
              ungroup()
            ,by="ID") %>% 
  dplyr::select(ID,edad,sexo,par,pheno) %>% 
  #mutate(sexo=forcats::fct_recode(sexo,
  #                                "sex1"="1", "sex0"="0")) %>% 
  mutate(sexo=as.factor(sexo),
         pheno=as.factor(pheno),
         edad=as.numeric(edad))
mcv_u <- Hmisc::upData(mcv %>% dplyr::select(-ID),
                         labels = c(edad="Age",
                                    sexo="Sex",
                                    par="Parasite density"
                                    ),
                         units = c(edad="(years)",
                                   par="(par/uL)"
                                   ),
                         levels = list(pheno=list("Asymptomatic"="asymptomatic",
                                                    "Symptomatic"="symptomatic"),
                                       sexo=list("Female"="0",
                                                    "Male"="1") #???
                                       )
                         )
Input object size:   3344 bytes;     4 variables     53 observations
New object size:    4608 bytes; 4 variables 53 observations
Hmisc::html(Hmisc::contents(mcv_u), maxlevels=10, levelType='table')

Data frame:mcv_u

53 observations and 4 variables, maximum # NAs:4  
NameLabelsUnitsLevelsClassStorageNAs
edadAge(years)integerinteger4
sexoSex2integer4
parParasite density(par/uL)integerinteger4
pheno2integer0

VariableLevels
sexoFemale
Male
phenoAsymptomatic
Symptomatic

s1 <- Hmisc::summaryM(sexo + edad + par ~ pheno,
               data=mcv_u,
               overall=FALSE, test=TRUE)
Error: `x` must be a numeric or a character vector
Hmisc::latex(s1, caption='Sample covariates',
      exclude1=TRUE, #npct='both', 
      test=TRUE , prtest="P",file="",
      digits=3, prn=FALSE,
      #prmsd=TRUE, brmsd=TRUE, #msdsize=mu$smaller2, #NOT-EVALUATE if PDF
      middle.bold=TRUE, long = FALSE,
      #legend.bottom = TRUE, #insert.bottom = TRUE, 
      what="%", html = TRUE, 
      width="100%"
      ) #change here for LaTeX PDF
Error in Hmisc::latex(s1, caption = "Sample covariates", exclude1 = TRUE,  : 
  object 's1' not found
readr::write_rds(mcv_u,"data/unap-rafa-covar.rds")

3 SEROLOGICAL CLASSIFICATION

3.1 To Do

  • Implement the mean / ROC / mixture models method

3.2 mixtools

3.2.1 check distributions

a <- mco %>% #filter(igg=="igg3") %>% 
  ggplot(aes(x=Ab.units
             #,fill=pheno
             #,fill=igg
             )) + theme_bw() +
  #scale_x_log10() +
  geom_density(alpha=.5,position = "identity") +
  geom_histogram(aes(x=Ab.units,..density..),
                 alpha=.5,position = "identity") +
  #theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  labs(title="AU linear distribution")
b <- mco %>% #filter(igg=="igg3") %>% 
  ggplot(aes(sample=Ab.units
             #,fill=pheno
             #,fill=igg
             )) +
  geom_qq(alpha=.2) +
  geom_qq_line(line.p = c(0.25, 0.75)) +
  labs(title="Gaussian quantile-quantile plot") +
  coord_cartesian(ylim = c(0,2000))
Rmisc::multiplot(a,b,cols = 2)

mco %>% 
  ggplot(aes(x=Ab.units
             #,fill=pheno
             )) + theme_bw() +
  #scale_x_log10() +
  geom_density(alpha=.5,position = "identity",adjust= 1/2
               ) + 
  geom_histogram(aes(x=Ab.units,..density..),
                 alpha=.5,position = "identity") + 
  facet_wrap(~igg, scales = "free",ncol = 5) +
  labs(title="AU linear distribution per IgG subtype")

3.2.2 apply mixtools

# source: http://tinyheero.github.io/2015/10/13/mixture-model.html
f <- mco %>% mutate(igg=as.factor(igg)) %>% 
  mutate(igg=forcats::fct_relevel(igg,"igg","igg1","igg2","igg3")) %>% .$igg
#library("mixtools")
#' Plot a Mixture Component
#' 
#' @param x Input data
#' @param mu Mean of component
#' @param sigma Standard deviation of component
#' @param lam Mixture weight of component
plot_mix_comps <- function(x, mu, sigma, lam) {
  lam * dnorm(x, mu, sigma)
}
set.seed(1)
#length(levels(f))
#wait <- mco %>% filter(igg=="igg2") %>% 
#  .$Ab.units %>% log()
llmix <- data_frame(igg=as.character(),
                    kpr=as.numeric(),
                    lik=as.numeric())
for (j in 2:3) {
    
    mixmdl_p <- normalmixEM(mco %>% 
                              #filter(igg==levels(f)[i]) %>% 
                              .$Ab.units #%>% log10()
                            , 
                            k = j)
    llmix <- llmix %>% 
      union(data_frame(igg="all",#levels(f)[i],
                       kpr=j,
                       lik=mixmdl_p$loglik))
    
  }
number of iterations= 37 
number of iterations= 60 
llmix %>% arrange(igg,desc(lik)) %>% mutate(aic=2*kpr-2*lik)
#
llmix <- data_frame(igg=as.character(),
                    kpr=as.numeric(),
                    lik=as.numeric())
for (i in 1:length(levels(f))) {
  
  for (j in 2:3) {
    
    mixmdl_p <- normalmixEM(mco %>% 
                              filter(igg==levels(f)[i]) %>% 
                              .$Ab.units #%>% log10()
                            , 
                            k = j)
    llmix <- llmix %>% 
      union(data_frame(igg=levels(f)[i],
                       kpr=j,
                       lik=mixmdl_p$loglik))
    
  }
  
}
number of iterations= 23 
One of the variances is going to zero;  trying new starting values.
One of the variances is going to zero;  trying new starting values.
One of the variances is going to zero;  trying new starting values.
number of iterations= 81 
number of iterations= 60 
number of iterations= 68 
number of iterations= 36 
number of iterations= 79 
number of iterations= 20 
number of iterations= 527 
number of iterations= 15 
number of iterations= 40 
llmix %>% arrange(igg,desc(lik)) %>% mutate(aic=2*kpr-2*lik) #%>% 
  #group_by(igg) %>% filter(lik==max(lik))
#mixmdl <- normalmixEM(wait, k = 3)
#mixmdl$loglik
### FOR ALL AB.UNITS (NO IGG SUBTYPES)
set.seed(1)
#for (i in 1:length(levels(f))) {
  
wait <- mco %>% #filter(igg==levels(f)[i]) %>% 
  .$Ab.units #%>% log10()
mixmdl <- normalmixEM(wait, k = 3)
number of iterations= 41 
###
r <- data.frame(x = mixmdl$x) %>%
  ggplot() +
  geom_histogram(aes(x, ..density..), 
                 #binwidth = 1, 
                 #colour = "black", 
                 #fill = "gray",
                 alpha=.5,position = "identity"
                 ) +
  stat_function(geom = "line", 
                fun = plot_mix_comps,
                args = list(mixmdl$mu[1], 
                            mixmdl$sigma[1], 
                            lam = mixmdl$lambda[1]),
                colour = "green", lwd = 1.5) +
  stat_function(geom = "line", 
                fun = plot_mix_comps,
                args = list(mixmdl$mu[2], 
                            mixmdl$sigma[2], 
                            lam = mixmdl$lambda[2]),
                colour = "blue", lwd = 1.5) +
  stat_function(geom = "line", 
                fun = plot_mix_comps,
                args = list(mixmdl$mu[3], 
                            mixmdl$sigma[3], 
                            lam = mixmdl$lambda[3]),
                colour = "red", lwd = 1.5) +
  ylab("Density") +
  xlab("Ab.units") +
  labs(title= paste0("Ab.units: ",
                     #ifelse(levels(f)[i]=="igg","IgG ",
                      #      ifelse(levels(f)[i]=="igg1","IgG1 ",
                        #           ifelse(levels(f)[i]=="igg2","IgG2 ",
                         #                 ifelse(levels(f)[i]=="igg3","IgG3 ","IgG4 ")
                          #                )
                          #         )
                          #  ),
                     "3-component distribution"
                     #,": LogLik=",
                     #mixmdl$loglik %>% format(digits=3)
                     )) 
  #+ scale_x_log10()
####
u <- 0.90 # 90% classification probability
post.df <- as.data.frame(cbind(x = mixmdl$x, mixmdl$posterior)) %>% 
  mutate(comp.12=comp.1+comp.2) %>% # sum probabilities of s+ and s++
  mutate(label = ifelse(comp.3 > u, "s-", 
                        ifelse(comp.12 > u, "s+", "s0"
                               #ifelse(comp.1 > u,"s++","s0")
                               ))) %>% 
  mutate(label=forcats::fct_relevel(label,"s-","s0","s+"#,"s++"
                                    ))
s <- post.df %>% 
  ggplot(aes(x = factor(label))) +
  geom_bar() +
  xlab("Component") +
  ylab("Number of Data Points") +
  labs(title="Classification")
###
t <- post.df %>% 
  ggplot() +
  #geom_line(aes(x,comp.1), colour="green", lwd = 1.5) +
  #geom_line(aes(x,comp.2), colour="blue", lwd = 1.5) +
  geom_line(aes(x,comp.12), colour="blue", lwd = 1.5) +
  geom_line(aes(x,comp.3), colour="red", lwd = 1.5) +
  geom_hline(yintercept = u, col = "black") +
  #geom_vline(xintercept = cutoffs[2], col = "black", lty=3) +
  #geom_vline(xintercept = cutoffs[1], col = "black", lty=3) +
  xlab("Ab.units") +
  ylab("classification probability") +
  labs(title="Cutoff")
Rmisc::multiplot(r,t,s,cols = 3)

  
#}
#sum(mco$Ab.units_log == mixmdl$x)
#length(mixmdl$x)
#sum(!post.df$x==mco$Ab.units_log)
msr <- inner_join(mco %>% rownames_to_column(),
           post.df %>%
             #dplyr::rename(Ab.units_log=x) %>% 
             dplyr::select(#Ab.units_log,
                           label) %>% 
             rownames_to_column(),
           by="rowname") #%>% 
  #mutate(test= Ab.units_log.x==Ab.units_log.y) %>% dplyr::count(test)
msr <- msr[FALSE,] #%>% glimpse()

3.2.3 2-component

set.seed(1)

for (i in 1:length(levels(f))) {
  
wait <- mco %>% filter(igg==levels(f)[i]) %>% 
  .$Ab.units #%>% log10()
mixmdl <- normalmixEM(wait, k = 3)
###
r <- data.frame(x = mixmdl$x) %>%
  ggplot() +
  geom_histogram(aes(x, ..density..), 
                 #binwidth = 1, 
                 #colour = "black", 
                 #fill = "gray",
                 alpha=.5,position = "identity"
                 ) +
  stat_function(geom = "line", 
                fun = plot_mix_comps,
                args = list(mixmdl$mu[1], 
                            mixmdl$sigma[1], 
                            lam = mixmdl$lambda[1]),
                colour = "red", lwd = 1.5) +
  stat_function(geom = "line", 
                fun = plot_mix_comps,
                args = list(mixmdl$mu[2], 
                            mixmdl$sigma[2], 
                            lam = mixmdl$lambda[2]),
                colour = "blue", lwd = 1.5) +
  #stat_function(geom = "line", 
  #              fun = plot_mix_comps,
  #              args = list(mixmdl$mu[3], 
  #                          mixmdl$sigma[3], 
  #                          lam = mixmdl$lambda[3]),
  #              colour = "green", lwd = 1.5) +
  ylab("Density") +
  xlab("Ab.units") +
  labs(title= paste0(ifelse(levels(f)[i]=="igg","IgG: ",
                            ifelse(levels(f)[i]=="igg1","IgG1: ",
                                   ifelse(levels(f)[i]=="igg2","IgG2: ",
                                          ifelse(levels(f)[i]=="igg3","IgG3 ","IgG4: ")
                                          )
                                   )
                            ),
                     "3-component distribution"
                     #,": LogLik=",
                     #mixmdl$loglik %>% format(digits=3)
                     )) 
  #+ scale_x_log10()

####
u <- 0.90 # 90% classification probability

post.df <- as.data.frame(cbind(x = mixmdl$x, mixmdl$posterior)) %>% 
  mutate(comp.sp=ifelse(mean(comp.2)>100,
                        comp.2+comp.3,
                        comp.1+comp.2)) %>% # sum probabilities of s+ and s++
  mutate(label = ifelse(comp.1 > u, "s-", 
                        #ifelse(comp.sp > u, "s+", "s0"
                        ifelse(comp.2 > u, "s+", "s0"
                               #ifelse(comp.1 > u,"s++","s0")
                               ))) %>% 
  mutate(label=forcats::fct_relevel(label,"s-","s0","s+"#,"s++"
                                    )) 

s <- post.df %>% 
  ggplot(aes(x = factor(label))) +
  geom_bar() +
  xlab("Component") +
  ylab("Number of Data Points") +
  labs(title="Classification")

###
t <- post.df %>% 
  ggplot() +
  #geom_line(aes(x,comp.1), colour="green", lwd = 1.5) +
  geom_line(aes(x,comp.2), colour="blue", lwd = 1.5) +
  #geom_line(aes(x,comp.sp), colour="blue", lwd = 1.5) +
  geom_line(aes(x,comp.1), colour="red", lwd = 1.5) +
  geom_hline(yintercept = u, col = "black") +
  #geom_vline(xintercept = 63.6, col = "black", lty=3) +
  #geom_vline(xintercept = 69.7, col = "black", lty=3) +
  xlab("Ab.units") +
  ylab("classification probability") +
  labs(title="Cutoff")


###
msr_p <- inner_join(mco %>%
                    filter(igg==levels(f)[i]) %>% 
                    rownames_to_column(),
           post.df %>%
             #dplyr::rename(Ab.units_log=x) %>% 
             dplyr::select(#Ab.units_log,
                           label) %>% 
             rownames_to_column(),
           by="rowname") #%>% 
  #mutate(test= Ab.units_log.x==Ab.units_log.y) %>% dplyr::count(test)


msr <- union(msr, msr_p)


Rmisc::multiplot(r,t,s,cols = 3)
  
}

3.2.4 three component distribution

  • Possible mistake for IgG2 and IgG4:
    • Definition of S- using only the 1st component and S+ using the 2nd and 3rd one, as was standardized for all the igg subtypes.
    • CORRECTION: If 2nd component have a mean AU lower than an ARBITRARY THRESHOLD, define S+ as the sum of only the 3rd component probabilities.
      • RESULT: a threshold of 100 give results as expected for igg2 and igg4 seropositivity.
        • IN REFERENCE: Rouhani 2015 (figure 2).
        • ACHIEVED CRITERIA: lower proportion of indetermined serology s0
      • ALTERNATIVE: a threshold of 40 may be convinient for igg4 in order to explain its:
        • significantly higher mean AU in symptomatics, and
        • strong association to symptomatic susceptibility.
        • According to the component CLASSIFICATION CRITERIA based on the proportion of s0, which is higher than the previous threshold, this is not the best classification.
        • However, if a boost or other phenomena (including a different genotype within the study population) that increase the proportion of IgG4 during a symptomatic episode is assumed, this may be the right one.
        • Interestingly, this 2nd component is full of symptomatic samples.
    • NOTE: Even though the mean of the 2nd component is higher than 100, for igg the threshold of seropositivity is lower than 40 AU, under the right criteria.
set.seed(1)
# i= 3
for (i in 1:length(levels(f))) {
  
wait <- mco %>% filter(igg==levels(f)[i]) %>% 
  .$Ab.units #%>% log10()
mixmdl <- normalmixEM(wait, k = 3)
###
r <- data.frame(x = mixmdl$x) %>%
  ggplot() +
  geom_histogram(aes(x, ..density..), 
                 #binwidth = 1, 
                 #colour = "black", 
                 #fill = "gray",
                 alpha=.5,position = "identity"
                 ) +
  stat_function(geom = "line", 
                fun = plot_mix_comps,
                args = list(mixmdl$mu[1], 
                            mixmdl$sigma[1], 
                            lam = mixmdl$lambda[1]),
                colour = "red", lwd = 1.5) +
  stat_function(geom = "line", 
                fun = plot_mix_comps,
                args = list(mixmdl$mu[2], 
                            mixmdl$sigma[2], 
                            lam = mixmdl$lambda[2]),
                colour = "blue", lwd = 1.5) +
  stat_function(geom = "line", 
                fun = plot_mix_comps,
                args = list(mixmdl$mu[3], 
                            mixmdl$sigma[3], 
                            lam = mixmdl$lambda[3]),
                colour = "green", lwd = 1.5) +
  ylab("Density") +
  xlab("Ab.units") +
  labs(title= paste0(ifelse(levels(f)[i]=="igg","IgG: ",
                            ifelse(levels(f)[i]=="igg1","IgG1: ",
                                   ifelse(levels(f)[i]=="igg2","IgG2: ",
                                          ifelse(levels(f)[i]=="igg3","IgG3 ","IgG4: ")
                                          )
                                   )
                            ),
                     "3-component distribution"
                     #,": LogLik=",
                     #mixmdl$loglik %>% format(digits=3)
                     )) 
  #+ scale_x_log10()
####
u <- 0.90 # 90% classification probability
post.df <- as.data.frame(cbind(x = mixmdl$x, mixmdl$posterior)) %>% 
  #mutate(comp.12=comp.1+comp.2,
  #       comp.23=comp.2+comp.3) %>% 
  mutate(comp.sp=if_else(rep(mixmdl$mu[2]>40,length(mixmdl$x)), # UMBRAL ARBITRARIO!!
                        comp.2+comp.3, # sero+ equals to the sum of comp 2+3
                        comp.3)) %>% # sero+ equals to the sum of comp 3
  mutate(comp.sn=if_else(rep(mixmdl$mu[2]>40,length(mixmdl$x)),
                        comp.1, # sero- equals to the sum of comp 1
                        comp.1+comp.2)) %>% # sero+ equals to the sum of comp 1+2
  mutate(label = if_else(comp.sn > u, "s-", 
                        ifelse(comp.sp > u, "s+", "s0"
                        #ifelse(comp.2 > u, "s+", #"s0"
                               #ifelse(comp.1 > u,"s++","s0")
                               ))) %>% 
  mutate(label=forcats::fct_relevel(label,"s-","s0","s+"#,"s++"
                                    )) 
s <- post.df %>% 
  ggplot(aes(x = factor(label))) +
  geom_bar() +
  xlab("Component") +
  ylab("Number of Data Points") +
  labs(title="Classification")
###
t <- post.df %>% 
  ggplot() +
  #geom_line(aes(x,comp.1), colour="green", lwd = 1.5) +
  #geom_line(aes(x,comp.2), colour="blue", lwd = 1.5) +
  #geom_point(aes(x,comp.sp), colour="blue", lwd = 1.5) +
  geom_line(aes(x,comp.sp), colour="blue", lwd = 1.5) +
  #geom_point(aes(x,comp.sn), colour="red", lwd = 1.5) +
  geom_line(aes(x,comp.sn), colour="red", lwd = 1.5) +
  geom_hline(yintercept = u, col = "black") +
  #geom_vline(xintercept = 63.6, col = "black", lty=3) +
  #geom_vline(xintercept = 69.7, col = "black", lty=3) +
  xlab("Ab.units") +
  ylab("classification probability") +
  labs(title="Cutoff")
###
msr_p <- inner_join(mco %>%
                    filter(igg==levels(f)[i]) %>% 
                    rownames_to_column(),
           post.df %>%
             #dplyr::rename(Ab.units_log=x) %>% 
             dplyr::select(#Ab.units_log,
                           label) %>% 
             rownames_to_column(),
           by="rowname") #%>% 
  #mutate(test= Ab.units_log.x==Ab.units_log.y) %>% dplyr::count(test)
msr <- union(msr, msr_p)
Rmisc::multiplot(r,t,s,cols = 3)
  
}
One of the variances is going to zero;  trying new starting values.
One of the variances is going to zero;  trying new starting values.
number of iterations= 71 
number of iterations= 73 
number of iterations= 22 
number of iterations= 475 
number of iterations= 34 

4 DATA FRAME

#mco
#msr
glimpse(
  msr %>% 
  mutate(ord=as.numeric(ord)) %>%  arrange(ord) %>% 
  dplyr::select(-Ab.units_log, -rowname)
)
Observations: 232
Variables: 16
$ Plate        <chr> "N1", "N1", "N1", "N1", "N1", "N1", "N1", "N1", "N1", "N1", "N1"...
$ ord          <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 1...
$ ID           <chr> "1570", "1843", "1856", "1910", "1969", "1977", "2131", "2134", ...
$ code         <chr> "1570_1", "1843_2", "1856_3", "1910_4", "1969_5", "1977_6", "213...
$ Type         <chr> "unk", "unk", "unk", "unk", "unk", "unk", "unk", "unk", "unk", "...
$ pheno        <chr> "asymptomatic", "symptomatic", "asymptomatic", "asymptomatic", "...
$ igg          <chr> "igg", "igg", "igg", "igg", "igg", "igg", "igg", "igg", "igg", "...
$ mean.OD      <dbl> 0.5485, 0.1825, 0.6260, 0.3070, 0.6220, 0.5310, 0.6615, 0.5795, ...
$ sd.OD        <dbl> 0.0205060967, 0.0007071068, 0.0141421356, 0.0098994949, 0.000000...
$ cv.OD        <dbl> 3.7385773, 0.3874558, 2.2591271, 3.2245912, 0.0000000, 7.1909164...
$ Ab.units     <dbl> 94.496989, 9.591621, 182.796839, 23.028486, 175.224706, 83.84476...
$ `Std. Error` <dbl> 27.4859252, 1.2766621, 63.3962207, 4.1773628, 60.1332973, 23.554...
$ Lower        <dbl> 32.319506, 6.703611, 39.384624, 13.578635, 39.193737, 30.560885,...
$ Upper        <dbl> 156.674471, 12.479631, 326.209054, 32.478337, 311.255675, 137.12...
$ par          <dbl> 4020, 1960, 1078, 406, 0, 2716, 498, 4866, 1094, 2010, 621, 824,...
$ label        <fctr> s+, s0, s+, s+, s+, s+, s+, s+, s-, s+, s+, s+, s-, s+, s+, s+,...
#summary(mdo)
readr::write_csv(
  msr %>% 
  mutate(ord=as.numeric(ord)) %>%  arrange(ord) %>% 
  dplyr::select(-Ab.units_log, -rowname)
                 ,"data/unap-rafael.csv")
readr::write_rds(
  msr %>% 
  mutate(ord=as.numeric(ord)) %>%  arrange(ord) %>% 
  dplyr::select(-Ab.units_log, -rowname)
  , "data/unap-rafael.rds")

5 STATISTICAL ANALYSIS PLAN

5.1 To Do

  • Do it

5.2 Sample size

mco %>% 
  group_by(igg) %>% dplyr::count(pheno)

5.3 Test Hypothesis

5.3.1 Mean AU

f <- mco %>% mutate(igg=as.factor(igg)) %>% .$igg
#mco <- mco %>% 
#  #dplyr::select(Ab.units,par) %>% 
#  mutate(Ab.units=log10(Ab.units),par=log10(par)) %>% 
#  filter(par!=-Inf) #%>% 
stt <- data_frame(##estimate=as.double(),
                  ##estimate1=as.double(),
                  ##estimate2=as.double(),
                  statistic=as.double(),
                  p.value=as.double(),
                  #parameter=as.double(),#
                  #conf.low=as.double(),#
                  #conf.high=as.double(),#
                  method=as.factor(NULL),
                  alternative=as.factor(NULL),
                  igg=as.character(),
                  lab=as.character())
for (l in 1:length(levels(f))) {
  
## Primero, Prueba de Hipótesis para comparar varianzas:
i <- mco %>% filter(igg==levels(f)[l]) %>% 
  var.test(Ab.units_log ~ pheno, data = .) %>% broom::tidy()
## Rpta: Bajo n.s. 0.05, F cae en Región de no-Rechazo de Hipótesis Nula (RnoRHo)
## Conclusión: Supuesto de igualdad de varianzas poblacionales SÍ es válido
## Segundo, Prueba de Hipótesis para comparar medias:
j <- mco %>% filter(igg==levels(f)[l]) %>% 
  #t.test(Ab.units_log ~ pheno, data = ., var.equal= i$p.value>0.05) %>%
  #wilcox.test(Ab.units_log ~ pheno, data = .) %>%#, 
  wilcox.test(Ab.units ~ pheno, data = .) %>%#, 
              #conf.int=TRUE) %>% 
  broom::tidy() %>%  #%>% format(digits=2)
  dplyr::select(-starts_with("estimate")) %>% 
  mutate(igg=levels(f)[l],
         lab= paste0(#"t=",#should be done -> mix variance equality test
                     #"W=",#non-parametric used in literature
                     #statistic %>% format(digits=2),
                     #", df=",parameter %>% format(digits=2),
                     #", P",ifelse(p.value<0.001,"<0.001",
                     "italic('P')",ifelse(p.value<0.001,"<0.001",
                                  paste0("==",p.value %>% format(digits=2))
                                  )
                     )
         )
stt <- stt %>% union(j)
}
stt <- stt %>% arrange(igg) %>% dplyr::select(igg,everything()) %>% 
  mutate(x=.5,
         y=.15) %>% 
  mutate(igg=forcats::fct_recode(igg,
                                 "IgG"="igg",
                                 "IgG1"="igg1",
                                 "IgG2"="igg2",
                                 "IgG3"="igg3",
                                 "IgG4"="igg4"
                                 ))
# plot
mco %>% #filter(igg==levels(f)[1]) %>% 
  mutate(igg=forcats::fct_recode(igg,
                                 "IgG"="igg",
                                 "IgG1"="igg1",
                                 "IgG2"="igg2",
                                 "IgG3"="igg3",
                                 "IgG4"="igg4"
                                 ),
         pheno=forcats::fct_recode(pheno,
                                   "Asymptomatic"="asymptomatic",
                                   "Symptomatic"="symptomatic")) %>%
  ggplot(aes(pheno,Ab.units)) +
  geom_boxplot(#position=position_dodge(0.8)
  ) +
  geom_dotplot(#aes(fill=sev_WHO), 
    binaxis='y', stackdir='center', alpha=.3, 
    dotsize=1#, position=position_dodge(0.8)
  ) +
  
  facet_wrap(~igg,ncol = 5) + 
  
  geom_text(aes(x,y,label=lab),data = stt,parse = T,
            #vjust=.5,hjust=0.05,size=3.5) +
            vjust=.5,hjust=0.05,size=3.5) + # if log10, then change it.
  
  #coord_cartesian(ylim = c(-300,2000)) + # if log10, then change it.
  scale_y_log10() +
  
  #labs(title="Test AU mean equality among phenotypes per IgG subtypes") +
  xlab("Carrier") + ylab("Antibody units (log scale)")

  • nota:
    • prueba de hipotesis no-paramétrica
    • ploteo en escala logística
msr %>% group_by(igg,pheno) %>% dplyr::summarise(min=min(Ab.units),
                                          q25=quantile(Ab.units) %>% .[2],
                                          mean=mean(Ab.units),
                                          q50=quantile(Ab.units) %>% .[3],
                                          q75=quantile(Ab.units) %>% .[4],
                                          max=max(Ab.units))

5.3.2 Proportion sero+

msr %>% dplyr::count(igg,label) %>% 
  group_by(igg) %>% mutate(tot=sum(n),prop= (n*100)/(sum(n))) %>% 
  filter(label=="s+")
msr %>% 
  mutate(label=forcats::fct_relevel(label,"s-","s+","s0"#,"s++"
                                    )) %>% 
  ggplot(aes(x=igg,fill=label)) +
  geom_bar(position = "fill") +
  #facet_grid(~igg) +
  labs(title="Proportion of seropositives per IgG subtype")

msr %>% dplyr::count(igg,pheno,label) %>% 
  group_by(igg,pheno) %>% mutate(tot=sum(n),prop= (n*100)/(sum(n))) %>% 
  filter(label=="s+") #%>% 
  #ungroup() %>% 
  #dplyr::select(-n,-label, -tot) %>% 
  #spread(pheno,prop)
msr %>% 
  dplyr::select(pheno,igg,label) %>% 
  #filter(igg==levels(f)[i]) %>% 
  #dplyr::select(-igg) %>% 
  group_by(igg,pheno,label) %>% dplyr::summarise(n=n()) %>% ungroup() %>% 
  spread(label,n)
ftt <- data_frame(igg=as.character(),
                  p.value=as.double(),
                  #estimate=as.double(),
                  method=as.character()#,
                  #alternative=as.factor()
                  )
for (i in 1:length(levels(f))) {
  
fst <- msr %>% 
  filter(!label=="s0") %>% 
  dplyr::select(pheno,igg,label) %>% 
  filter(igg==levels(f)[i]) %>% 
  dplyr::select(-igg) %>% 
  group_by(pheno,label) %>% dplyr::summarise(n=n()) %>% ungroup() %>% 
  #spread(label,n) %>% as.matrix() %>% 
  reshape2::acast(pheno ~ label,
                  value.var = "n") #%>% #class()
fst[is.na(fst)] <- 0
ftt <- ftt %>% 
  union(
  fisher.test(fst) %>% broom::tidy() %>% 
    mutate(igg=levels(f)[i]) %>% 
    dplyr::select(igg,p.value,
                  #estimate,
                  method#,alternative
                  )
)
  
}
ftt %>% arrange(igg) %>% 
  mutate(sig=ifelse(p.value<0.05,"signif","not-signif"))
fttt <- ftt %>% arrange(igg) %>% dplyr::select(igg,everything()) %>% 
  mutate(x=.5,
         y=-.05) %>% 
  mutate(lab= paste0("italic('P')",ifelse(p.value<0.001,"<0.001",
                                  paste0("==",p.value %>% format(digits=2))
                                  )
                     )
         ) %>% 
  mutate(lab=stringr::str_replace(lab,"(P = 0\\...)(.+)","\\1")) %>% 
  mutate(igg=forcats::fct_recode(igg,
                                 "IgG"="igg",
                                 "IgG1"="igg1",
                                 "IgG2"="igg2",
                                 "IgG3"="igg3",
                                 "IgG4"="igg4"
                                 ))
msr %>% 
  mutate(igg=forcats::fct_recode(igg,
                                 "IgG"="igg",
                                 "IgG1"="igg1",
                                 "IgG2"="igg2",
                                 "IgG3"="igg3",
                                 "IgG4"="igg4"
                                 ),
         pheno=forcats::fct_recode(pheno,
                                   "Asymptomatic"="asymptomatic",
                                   "Symptomatic"="symptomatic")) %>%
  mutate(label=forcats::fct_relevel(label,"s-","s+","s0"#,"s++"
                                    )) %>% 
  full_join(fttt %>% dplyr::select(igg,lab,y,x),by = "igg") %>% 
  mutate(lab=if_else(label=="s+",lab,NA_character_)) %>% 
  arrange(lab) %>% 
  mutate(lab=if_else(igg==lead(igg),NA_character_,lab)) %>% 
  filter(!label=="s0") %>% 
  ggplot(aes(x=pheno,fill=label)) +
  geom_bar(position = "fill") +
  facet_grid(~igg) +
  
  coord_cartesian(ylim = c(-.12,1)) +
  geom_text(aes(x=x,
                y=y,label=lab),parse = T,#position = "fill",#data = fttt,,
            ##vjust=.5,hjust=0.05,size=3.5) +
            vjust=1,hjust=0.0005,size=3.5
            ) + # if log10, then change it.
  
  #labs(title="Proportion of seropositives among phenotypes per IgG subtype") +
  xlab("Carrier") + ylab("Proportion") +
  scale_fill_grey(#start = 0, end = .9,
                  name="Serology",labels=c("Negative","Positive"#,"Indeterminate"
                                           ))

##aqui
s1 <- Hmisc::summaryM(label
                      ~ pheno,
               data=msr %>% filter(igg=="igg"),
               overall=FALSE, test=TRUE)
Hmisc::latex(s1, caption='Sample covariates',
      exclude1=TRUE, npct='both', 
      digits=3,
      #prmsd=TRUE, brmsd=TRUE, #msdsize=mu$smaller2, #NOT-EVALUATE if PDF
      middle.bold=TRUE, long = TRUE,
      #legend.bottom = TRUE, #insert.bottom = TRUE, 
      what="%", html = TRUE, width="100%"
      ) #change here for LaTeX PDF
Sample covariates.
asymptomatic
N=27
symptomatic
N=29
Test Statistic
label χ22=3.41, P=0.182
    s- 7% 227 24% 729
    s0 4% 127 7% 229
    s+ 89% 2427 69% 2029

Test used: Pearson test .
##aqui
s1 <- Hmisc::summaryM(label
                      ~ pheno,
               data=msr %>% filter(igg=="igg1"),
               overall=FALSE, test=TRUE)
Hmisc::latex(s1, caption='Sample covariates',
      exclude1=TRUE, npct='both', 
      digits=3,
      #prmsd=TRUE, brmsd=TRUE, #msdsize=mu$smaller2, #NOT-EVALUATE if PDF
      middle.bold=TRUE, long = TRUE,
      #legend.bottom = TRUE, #insert.bottom = TRUE, 
      what="%", html = TRUE, width="100%"
      ) #change here for LaTeX PDF
Sample covariates.
asymptomatic
N=24
symptomatic
N=20
Test Statistic
label χ22=2.18, P=0.336
    s- 12% 324 30% 620
    s0 17% 424 10% 220
    s+ 71% 1724 60% 1220

Test used: Pearson test .
##aqui
s1 <- Hmisc::summaryM(label
                      ~ pheno,
               data=msr %>% filter(igg=="igg2"),
               overall=FALSE, test=TRUE)
Hmisc::latex(s1, caption='Sample covariates',
      exclude1=TRUE, npct='both', 
      digits=3,
      #prmsd=TRUE, brmsd=TRUE, #msdsize=mu$smaller2, #NOT-EVALUATE if PDF
      middle.bold=TRUE, long = TRUE,
      #legend.bottom = TRUE, #insert.bottom = TRUE, 
      what="%", html = TRUE, width="100%"
      ) #change here for LaTeX PDF
Sample covariates.
asymptomatic
N=24
symptomatic
N=20
Test Statistic
label χ22=4.73, P=0.094
    s- 83% 2024 70% 1420
    s0 8% 224 0% 020
    s+ 8% 224 30% 620

Test used: Pearson test .
##aqui
s1 <- Hmisc::summaryM(label
                      ~ pheno,
               data=msr %>% filter(igg=="igg3"),
               overall=FALSE, test=TRUE)
Hmisc::latex(s1, caption='Sample covariates',
      exclude1=TRUE, npct='both', 
      digits=3,
      #prmsd=TRUE, brmsd=TRUE, #msdsize=mu$smaller2, #NOT-EVALUATE if PDF
      middle.bold=TRUE, long = TRUE,
      #legend.bottom = TRUE, #insert.bottom = TRUE, 
      what="%", html = TRUE, width="100%"
      ) #change here for LaTeX PDF
Sample covariates.
asymptomatic
N=24
symptomatic
N=20
Test Statistic
label χ22=1.59, P=0.451
    s- 29% 724 20% 420
    s0 0% 024 5% 120
    s+ 71% 1724 75% 1520

Test used: Pearson test .
##aqui
s1 <- Hmisc::summaryM(label
                      ~ pheno,
               data=msr %>% filter(igg=="igg4"),
               overall=FALSE, test=TRUE)
Hmisc::latex(s1, caption='Sample covariates',
      exclude1=TRUE, npct='both', 
      digits=3,
      #prmsd=TRUE, brmsd=TRUE, #msdsize=mu$smaller2, #NOT-EVALUATE if PDF
      middle.bold=TRUE, long = TRUE,
      #legend.bottom = TRUE, #insert.bottom = TRUE, 
      what="%", html = TRUE, width="100%"
      ) #change here for LaTeX PDF
Sample covariates.
asymptomatic
N=24
symptomatic
N=20
Test Statistic
label χ22=25.4, P<0.001
    s- 54% 1324 0% 020
    s0 21% 524 0% 020
    s+ 25% 624 100% 2020

Test used: Pearson test .

5.3.3 Distribution sero+

  • the minimum value of the sero+ distribution is close to the cut-off and could be assumed as its value, but is not exactly that value.
msr %>% 
  mutate(label=forcats::fct_relevel(label,"s-","s+","s0"#,"s++"
                                    )) %>% 
  ggplot(aes(x=Ab.units,fill=label)) +
  #geom_bar(position = "fill") +
  geom_histogram(position = "stack") +
  facet_grid(~igg,scales = "free") +
  labs(title="Proportion of seropositives")

msr %>% 
  filter(label=="s+") %>% 
  group_by(igg) %>% dplyr::summarise(min=min(Ab.units),
                              q25=quantile(Ab.units) %>% .[2],
                              mean=mean(Ab.units),
                              q50=quantile(Ab.units) %>% .[3],
                              q75=quantile(Ab.units) %>% .[4],
                              max=max(Ab.units))
msr %>% 
  mutate(label=forcats::fct_relevel(label,"s-","s+","s0"#,"s++"
                                    )) %>% 
  ggplot(aes(x=Ab.units,fill=label)) +
  #geom_bar(position = "fill") +
  #scale_x_log10() +
  geom_histogram(position = "stack") +
  facet_grid(pheno~igg,scales = "free") +
  labs(title="Proportion of seropositives")

5.4 Correlation

5.4.1 IgG subtypes

mco %>% dim()
[1] 232  16
u <- mco %>% filter(pheno=="asymptomatic") %>% 
  dplyr::select(ID,igg,Ab.units) %>% 
  #mutate(Ab.units=log10(Ab.units)) %>% 
  spread(igg,Ab.units) %>% 
  dplyr::select(-ID) %>% 
  mutate(pheno="asymptomatic") %>% 
  mutate(pheno=forcats::fct_recode(pheno,
                                   "Asymptomatic"="asymptomatic",
                                   "Symptomatic"="symptomatic")) %>%
  dplyr::rename("IgG"="igg","IgG1"="igg1",
                "IgG2"="igg2","IgG3"="igg3","IgG4"="igg4")
v <- mco %>% filter(pheno=="symptomatic") %>% 
  dplyr::select(ID,igg,Ab.units) %>% 
  #mutate(Ab.units=log10(Ab.units)) %>% 
  spread(igg,Ab.units) %>% 
  dplyr::select(-ID) %>% 
  mutate(pheno="symptomatic") %>% 
  mutate(pheno=forcats::fct_recode(pheno,
                                   "Asymptomatic"="asymptomatic",
                                   "Symptomatic"="symptomatic")) %>%
  dplyr::rename("IgG"="igg","IgG1"="igg1",
                "IgG2"="igg2","IgG3"="igg3","IgG4"="igg4")
#par(mfrow=c(1,3))
a <- union(u,v) %>% 
  dplyr::select(-pheno) 
a %>% 
  PerformanceAnalytics::chart.Correlation(method = "spearman",main="all",histogram = F)

b <- union(u,v) %>% 
  filter(pheno=="Asymptomatic") %>% 
  dplyr::select(-pheno) 
b %>% 
  PerformanceAnalytics::chart.Correlation(method = "spearman",main="asymptomatic",histogram = F)

c <- union(u,v) %>% 
  filter(pheno=="Symptomatic") %>% 
  dplyr::select(-pheno) 
c %>% 
  PerformanceAnalytics::chart.Correlation(method = "spearman",main="symptomatic",histogram = F)

#a
#par(mfrow=c(1,1))
#d <- c
#d <- b
#d <- c
#cor(d[which(complete.cases(d)),],method = "spearman")
cor.ext <- function(d) {#d <- a
e <- Hmisc::rcorr(as.matrix(d[which(complete.cases(d)),]), type="spearman")
#e
rr <- e$r %>% as.data.frame() %>% mutate_all(funs(if_else(.==1,NA_real_,.))) %>% 
  gather(ig,vl) %>% mutate(vl=format(vl,digits = 2)) %>% mutate(vl=as.numeric(vl)) %>% 
  group_by(ig) %>% 
  mutate(id=1:n()) %>% 
  spread(ig,vl) %>% dplyr::select(-id) %>% rownames_to_column() #%>% dplyr::select(-rowname)
pp <- e$P %>% as.data.frame() %>% mutate_all(funs(if_else(.<0.001,111,
                                                    if_else(.<0.01,11,
                                                            if_else(.<0.05,1,0))))) %>% 
  mutate_all(as.character) %>% 
  mutate_all(funs(if_else(.=="111","(***)",
                          if_else(.=="11","(**)",
                                  if_else(.=="1","(*)","(ns)"))))) %>% rownames_to_column()
ee <- rr %>% gather(ig,vl) %>% mutate(vl="") %>% group_by(ig) %>% mutate(id=1:n()) %>% spread(ig,vl) %>% dplyr::select(-id) %>% dplyr::select(rowname,everything())
ppp <- as.matrix(pp)
rrr <- as.matrix(rr)
eee <- as.matrix(ee)
#eee <- rrr
eee[1,3] <- paste(rrr[1,3],ppp[1,3])
eee[1:2,4] <- paste(rrr[1:2,4],ppp[1:2,4])
#eee[2,4] <- paste(rrr[2,4],ppp[2,4])
eee[1:3,5] <- paste(rrr[1:3,5],ppp[1:3,5])
#eee[2,5] <- paste(rrr[2,5],ppp[2,5])
#eee[3,5] <- paste(rrr[3,5],ppp[3,5])
eee[1:4,6] <- paste(rrr[1:4,6],ppp[1:4,6])
ext <- eee %>% as_data_frame() %>% mutate(rowname=colnames(.)[-1]) #%>% #as.matrix()
  #dplyr::rename("subtype"=rowname)
return(ext)
  
}
aa <- cor.ext(a) %>% #dplyr::rename("all"=rowname) %>% 
  column_to_rownames() %>% as.matrix() #%>% knitr::kable(format = "latex")
bb <- cor.ext(b) %>% #dplyr::rename("asympt"=rowname) %>% 
  column_to_rownames() %>% as.matrix()
cc <- cor.ext(c) %>% #dplyr::rename("sympt"=rowname) %>% 
  column_to_rownames() %>% as.matrix()
readr::write_rds(aa,"data/cor_all.rds")
readr::write_rds(bb,"data/cor_asymp.rds")
readr::write_rds(cc,"data/cor_sympt.rds")
aa
     IgG IgG1         IgG2        IgG3         IgG4        
IgG  ""  "0.53 (***)" "0.45 (**)" "0.54 (***)" "-0.12 (ns)"
IgG1 ""  ""           "0.24 (ns)" "0.47 (**)"  " 0.16 (ns)"
IgG2 ""  ""           ""          "0.69 (***)" " 0.25 (ns)"
IgG3 ""  ""           ""          ""           " 0.38 (*)" 
IgG4 ""  ""           ""          ""           ""          
bb
     IgG IgG1         IgG2         IgG3          IgG4         
IgG  ""  "0.548 (**)" "0.307 (ns)" "0.618 (**)"  "-0.073 (ns)"
IgG1 ""  ""           "0.062 (ns)" "0.643 (***)" " 0.336 (ns)"
IgG2 ""  ""           ""           "0.413 (*)"   " 0.103 (ns)"
IgG3 ""  ""           ""           ""            " 0.277 (ns)"
IgG4 ""  ""           ""           ""            ""           
cc
     IgG IgG1       IgG2         IgG3         IgG4       
IgG  ""  "0.52 (*)" "0.77 (***)" "0.68 (***)" "0.33 (ns)"
IgG1 ""  ""         "0.34 (ns)"  "0.36 (ns)"  "0.22 (ns)"
IgG2 ""  ""         ""           "0.90 (***)" "0.57 (**)"
IgG3 ""  ""         ""           ""           "0.50 (*)" 
IgG4 ""  ""         ""           ""           ""         
#knitr::kable(cc,"latex")
ax <- t(as.matrix(c("","","","","")))
rownames(ax) <- "All individuals"
colnames(ax) <- c("IgG","IgG1","IgG2","IgG3","IgG4")
bx <- t(as.matrix(c("","","","","")))
rownames(bx) <- "Asymptomatics"
colnames(bx) <- c("IgG","IgG1","IgG2","IgG3","IgG4")
cx <- t(as.matrix(c("","","","","")))
rownames(cx) <- "Symptomatics"
colnames(cx) <- c("IgG","IgG1","IgG2","IgG3","IgG4")
dd <- rbind(ax,aa,bx,bb,cx,cc)[-c(6,12,18),-1]
readr::write_rds(dd,"data/cor_full.rds")
#mco %>% 
#  dplyr::select(pheno,igg,Ab.units,par) %>% 
#  GGally::ggpairs(mapping = aes(color = pheno))
union(u,v) %>% 
  dplyr::rename("Status"=pheno) %>% 
  GGally::ggscatmat(color = "Status",corMethod = "spearman") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  labs(title="Correlation between IgG subtypes per phenotype")# +scale_fill_grey(start = 0, end = .9)

# correlación general y estratificada
#union(u,v) %>% 
#  GGally::ggpairs(mapping = aes(color = pheno))

5.4.2 parasitemia

mco %>% 
  ggplot(aes(Ab.units,fill=pheno)) +
  geom_density(position = "identity",alpha=0.6) +
  #geom_rug() + 
  scale_x_log10()

mco %>% #summary(mco$par)
  ggplot(aes(par,fill=pheno)) +
  geom_density(position = "identity",alpha=0.6) +
  #geom_rug() + 
  scale_x_log10()

mco %>% 
  ggplot(aes(Ab.units,par,fill=pheno)) +
  geom_point(aes(colour=pheno)) +
  scale_x_log10() + 
  scale_y_log10() +
  facet_grid(pheno~igg,scales = "free") +
  geom_smooth(aes(colour=pheno),method = lm)

u <- mco %>% filter(pheno=="asymptomatic") %>% 
  dplyr::select(ID,igg,Ab.units,par) %>% 
  #mutate(Ab.units=log10(Ab.units)) %>% 
  spread(igg,Ab.units) %>% 
  dplyr::select(-ID)

v <- mco %>% filter(pheno=="symptomatic") %>% 
  dplyr::select(ID,igg,Ab.units,par) %>% 
  #mutate(Ab.units=log10(Ab.units)) %>% 
  spread(igg,Ab.units) %>% 
  dplyr::select(-ID) 

#union(u,v) %>% 
#  PerformanceAnalytics::chart.Correlation(histogram = FALSE,method = "spearman")
mco %>% 
  ggplot(aes(Ab.units,par)) +
  geom_point(aes(colour=pheno)) +
  scale_x_log10() +
  scale_y_log10() +
  facet_grid(pheno~igg
             #,scales = "free"
             ) +
  geom_smooth(method = lm)
f <- mco %>% mutate(igg=as.factor(igg)) %>% .$igg
g <- mco %>% mutate(pheno=as.factor(pheno)) %>% .$pheno
#mco <- mco %>% 
#  #dplyr::select(Ab.units,par) %>% 
#  mutate(Ab.units=log10(Ab.units),par=log10(par)) %>% 
#  filter(par!=-Inf) #%>% 
stt <- data_frame(estimate=as.double(),
                  ##estimate1=as.double(),
                  ##estimate2=as.double(),
                  statistic=as.double(),
                  p.value=as.double(),
                  parameter=as.double(),#
                  conf.low=as.double(),#
                  conf.high=as.double(),#
                  method=as.factor(NULL),
                  alternative=as.factor(NULL),
                  igg=as.character(),
                  pheno=as.character(),
                  signf=as.character(),
                  rho=as.character(),
                  lab=as.character())
for (l in 1:length(levels(f))) {
  
  for (k in 1:length(levels(g))) {
    
## Primero,
j <- mco %>% filter(par!=0) %>%  filter(igg==levels(f)[l] & pheno==levels(g)[k]) %>% #l #k
  #t.test(Ab.units_log ~ pheno, data = ., var.equal= i$p.value>0.05) %>%
  #wilcox.test(Ab.units_log ~ pheno, data = .) %>%#, 
              #conf.int=TRUE) %>% 
  cor.test(~ log10(Ab.units) + log10(par), 
           data = ., method = "pearson") %>% 
  broom::tidy() %>%  #%>% format(digits=2)
  #dplyr::select(-starts_with("estimate")) %>% 
  mutate(igg=levels(f)[l],#l
         pheno=levels(g)[k],#k
         signf=if_else(p.value<0.001,"ooo",
                       if_else(p.value<0.01,"oo",
                               if_else(p.value<0.05,"o","ns"#""#
                                       ))),
         rho= estimate %>% format(digits=2),
         lab= paste0(#"t=",#should be done -> mix variance equality test
                     #"W=",#non-parametric used in literature
                     #"S=",f$statistic,", rho="
                     "rho=",estimate %>% format(digits=2),
                     "\nP",ifelse(p.value<0.001,"<0.001",
                                  paste0("=",p.value %>% format(digits=2)))
                     )
         )
#i <- mco %>% filter(igg==levels(f)[l] & pheno==levels(g)[k]) %>% #l #k
#  #t.test(Ab.units_log ~ pheno, data = ., var.equal= i$p.value>0.05) %>%
#  #wilcox.test(Ab.units_log ~ pheno, data = .) %>%#, 
#              #conf.int=TRUE) %>% 
#  cor.test(~ Ab.units + par, 
#           data = ., method = "spearman") %>% 
#  broom::tidy() %>%  #%>% format(digits=2)
#  #dplyr::select(-starts_with("estimate")) %>% 
#  mutate(igg=levels(f)[l],#l
#         pheno=levels(g)[k],#k
#         signf=if_else(p.value<0.001,"(***)",
#                       if_else(p.value<0.01,"(**)",
#                               if_else(p.value<0.05,"(*)","(ns)"))),
#         rho= estimate %>% format(digits=2),
#         lab= paste0(#"t=",#should be done -> mix variance equality test
#                     #"W=",#non-parametric used in literature
#                     #"S=",f$statistic,", rho="
#                     "rho=",estimate %>% format(digits=2)#,
#                     #"\nP",ifelse(p.value<0.001,"<0.001",
#                      #            paste0("=",p.value %>% format(digits=2)))
#                     )
#         )
stt <- stt %>% union(j) #%>% union(i)
    
  }
}
sttt <- stt %>% arrange(igg,pheno) %>% dplyr::select(igg,pheno,everything()) %>% 
  mutate(x=if_else(igg=="igg1"|igg=="igg3"|igg=="igg4",10,
                   if_else(igg=="igg2",.7,.1)),
         y=60000)
# plot
specie_name <- c("asymptomatic"="Asymptomatic","symptomatic"="Symptomatic",
                 "igg"="IgG","igg1"="IgG1","igg2"="IgG2","igg3"="IgG3","igg4"="IgG4"
                 )
mco %>% 
  filter(par!=0) %>% 
  ggplot(aes(Ab.units,par)) +
  geom_point(#aes(colour=pheno)
             ) +
  scale_x_log10() +
  scale_y_log10(limits=c(100,65000)
                ) +
  facet_grid(pheno~igg,labeller = as_labeller(specie_name)
             ,scales = "free_x"
             ) +
  #geom_smooth(method = lm,se=F,col="grey50",lwd=.5) +
  #geom_smooth(method = loess,se=F,col="grey50",lwd=.5) +
  
  geom_text(aes(x,y,label=paste0("r","==",
                                 rho,"^",signf
                                 )),data = sttt, parse = T,
            vjust=1,hjust=0.05,size=3.5) +
  
  #labs(#title="Correlation between AU and parasitemia per IgG subtype and phenotype",
   #    caption="oo: P < 0.01; o: P < 0.05; ns: non-significant"
    #   ) +
  xlab("Antibody units (log scale)") + 
  ylab(expression(paste("Parasite/",mu,"L"," (log scale)"))) #+ #ylab("Parasite/uL") +

  #coord_cartesian(ylim = c(0,20000))
  #scale_color_grey(#start = 0, end = .9,
   #               name="Carrier",labels=c("Asymptomatic","Symptomatic"#,"Indeterminate"
    #                                       ))
d <- data.frame(x=1:3,y=1:3)
qplot(x, y, data=d) + geom_text(aes(2, 2.5,
              label="rho~and~some~other~text"), parse=TRUE)

f <- mco %>% mutate(igg=as.factor(igg)) %>% .$igg
#mco <- mco %>% 
#  #dplyr::select(Ab.units,par) %>% 
#  mutate(Ab.units=log10(Ab.units),par=log10(par)) %>% 
#  filter(par!=-Inf) #%>% 
stt <- data_frame(estimate=as.double(),
                  ##estimate1=as.double(),
                  ##estimate2=as.double(),
                  statistic=as.double(),
                  p.value=as.double(),
                  #parameter=as.double(),#
                  #conf.low=as.double(),#
                  #conf.high=as.double(),#
                  method=as.factor(NULL),
                  alternative=as.factor(NULL),
                  igg=as.character(),
                  lab=as.character())
for (l in 1:length(levels(f))) {
  
## Primero,
j <- mco %>% filter(igg==levels(f)[l]) %>% #l
  #t.test(Ab.units_log ~ pheno, data = ., var.equal= i$p.value>0.05) %>%
  #wilcox.test(Ab.units_log ~ pheno, data = .) %>%#, 
              #conf.int=TRUE) %>% 
  cor.test(~ Ab.units + par, 
           data = ., method = "spearman") %>% 
  broom::tidy() %>%  #%>% format(digits=2)
  #dplyr::select(-starts_with("estimate")) %>% 
  mutate(igg=levels(f)[l],#l
         lab= paste0(#"t=",#should be done -> mix variance equality test
                     #"W=",#non-parametric used in literature
                     #"S=",f$statistic,", rho="
                     "rho=",estimate %>% format(digits=2),
                     "\nP",ifelse(p.value<0.001,"<0.001",
                                  paste0("=",p.value %>% format(digits=2)))
                     )
         )
stt <- stt %>% union(j)
}
stt <- stt %>% arrange(igg) %>% dplyr::select(igg,everything()) %>% 
  mutate(x=.1,
         y=200)
# plot
mco %>% #filter(igg==levels(f)[1]) %>% 
  ggplot(aes(Ab.units,par)) +
  geom_point() +
  scale_x_log10() +
  scale_y_log10() +
  geom_smooth(method = lm,se=F,col="grey50",lwd=.5) +
  #geom_smooth(method = loess,se=F,col="grey50",lwd=.5) +
  geom_text(aes(x,y,label=lab),data = stt,
            vjust=.5,hjust=0.05,size=3.5) +
  facet_grid(~igg
             #,scales = "free"
             ) +
  #facet_wrap(~igg,ncol = 5)
  labs(title="Correlation between AU and parasitemia per IgG subtype")

5.4.3 age

age <- mco %>% 
  dplyr::select(ID, code, pheno, igg, Ab.units) %>% 
  full_join(mcv,by=c("ID","pheno"))
age %>% #summary(age$edad)
  ggplot(aes(Ab.units,fill=pheno)) +
  geom_density(position = "identity",alpha=0.7) +
  facet_wrap(~igg,scales = "free",ncol = 5) #+scale_x_log10()

age %>% #summary(age$edad)
  ggplot(aes(edad,fill=pheno)) +
  geom_density(position = "identity",alpha=0.7)

f <- age %>% mutate(igg=as.factor(igg)) %>% .$igg
g <- age %>% mutate(pheno=as.factor(pheno)) %>% .$pheno
#mco <- mco %>% 
#  #dplyr::select(Ab.units,par) %>% 
#  mutate(Ab.units=log10(Ab.units),par=log10(par)) %>% 
#  filter(par!=-Inf) #%>% 
stt <- data_frame(estimate=as.double(),
                  ##estimate1=as.double(),
                  ##estimate2=as.double(),
                  statistic=as.double(),
                  p.value=as.double(),
                  #parameter=as.double(),#
                  #conf.low=as.double(),#
                  #conf.high=as.double(),#
                  method=as.factor(NULL),
                  alternative=as.factor(NULL),
                  igg=as.character(),
                  pheno=as.character(),
                  signf=as.character(),
                  rho=as.character(),
                  lab=as.character())
for (l in 1:length(levels(f))) {
  
  for (k in 1:length(levels(g))) {
    
## Primero,
j <- age %>% filter(igg==levels(f)[l] & pheno==levels(g)[k]) %>% #l #k
  #t.test(Ab.units_log ~ pheno, data = ., var.equal= i$p.value>0.05) %>%
  #wilcox.test(Ab.units_log ~ pheno, data = .) %>%#, 
              #conf.int=TRUE) %>% 
  cor.test(~ Ab.units + edad, 
           data = ., method = "spearman") %>% 
  broom::tidy() %>%  #%>% format(digits=2)
  #dplyr::select(-starts_with("estimate")) %>% 
  mutate(igg=levels(f)[l],#l
         pheno=levels(g)[k],#k
         signf=if_else(p.value<0.001,"ooo",
                       if_else(p.value<0.01,"oo",
                               if_else(p.value<0.05,"o","ns"#""#
                                       ))),
         rho= estimate %>% format(digits=2),
         lab= paste0(#"t=",#should be done -> mix variance equality test
                     #"W=",#non-parametric used in literature
                     #"S=",f$statistic,", rho="
                     "rho=",estimate %>% format(digits=2),
                     "\nP",ifelse(p.value<0.001,"<0.001",
                                  paste0("=",p.value %>% format(digits=2)))
                     )
         )
#i <- age %>% filter(igg==levels(f)[l] & pheno==levels(g)[k]) %>% #l #k
#  #t.test(Ab.units_log ~ pheno, data = ., var.equal= i$p.value>0.05) %>%
#  #wilcox.test(Ab.units_log ~ pheno, data = .) %>%#, 
#              #conf.int=TRUE) %>% 
#  cor.test(~ Ab.units + edad, 
#           data = ., method = "spearman") %>% 
#  broom::tidy() %>%  #%>% format(digits=2)
#  #dplyr::select(-starts_with("estimate")) %>% 
#  mutate(igg=levels(f)[l],#l
#         pheno=levels(g)[k],#k
#         lab= paste0(#"t=",#should be done -> mix variance equality test
#                     #"W=",#non-parametric used in literature
#                     #"S=",f$statistic,", rho="
#                     "rho=",estimate %>% format(digits=2),
#                     "\nP",ifelse(p.value<0.001,"<0.001",
#                                  paste0("=",p.value %>% format(digits=2)))
#                     )
#         )
stt <- stt %>% union(j) #%>% union(i)
    
  }
}
sttu <- stt %>% arrange(igg,pheno) %>% dplyr::select(igg,pheno,everything()) %>% 
  mutate(x=.1,
         y=78)
# plot
specie_name <- c("asymptomatic"="Asymptomatic","symptomatic"="Symptomatic",
                 "igg"="IgG","igg1"="IgG1","igg2"="IgG2","igg3"="IgG3","igg4"="IgG4"
                 )
age %>% 
  ggplot(aes(Ab.units,edad)) +
  geom_point(#aes(colour=pheno)
             ) +
  #scale_x_log10() +
  #scale_y_log10() +
  facet_grid(pheno~igg,labeller = as_labeller(specie_name)
             ,scales = "free_x"
             ) +
  #geom_smooth(method = lm,se=F,col="grey50",lwd=.5) +
  #geom_smooth(method = loess,se=F,col="grey50",lwd=.5) +
  geom_text(aes(x,y,label=paste0("rho","==",
                                 rho,"^",signf
                                 )),data = sttu, parse = T,
            vjust=.5,hjust=0.05,size=3.5) +
  #labs(title="Correlation between AU and parasitemia per IgG subtype and phenotype") +
  xlab("Antibody units") + ylab("Age (years)") +
  coord_cartesian(ylim = c(0,85))

  #scale_color_grey(#start = 0, end = .9,
   #               name="Carrier",labels=c("Asymptomatic","Symptomatic"#,"Indeterminate"
    #                                       ))
f <- age %>% mutate(igg=as.factor(igg)) %>% .$igg
#mco <- mco %>% 
#  #dplyr::select(Ab.units,par) %>% 
#  mutate(Ab.units=log10(Ab.units),par=log10(par)) %>% 
#  filter(par!=-Inf) #%>% 
stt <- data_frame(estimate=as.double(),
                  ##estimate1=as.double(),
                  ##estimate2=as.double(),
                  statistic=as.double(),
                  p.value=as.double(),
                  #parameter=as.double(),#
                  #conf.low=as.double(),#
                  #conf.high=as.double(),#
                  method=as.factor(NULL),
                  alternative=as.factor(NULL),
                  igg=as.character(),
                  lab=as.character())
for (l in 1:length(levels(f))) {
  
## Primero,
j <- age %>% filter(igg==levels(f)[l]) %>% #l
  #t.test(Ab.units_log ~ pheno, data = ., var.equal= i$p.value>0.05) %>%
  #wilcox.test(Ab.units_log ~ pheno, data = .) %>%#, 
              #conf.int=TRUE) %>% 
  cor.test(~ Ab.units + edad, 
           data = ., method = "spearman") %>% 
  broom::tidy() %>%  #%>% format(digits=2)
  #dplyr::select(-starts_with("estimate")) %>% 
  mutate(igg=levels(f)[l],#l
         lab= paste0(#"t=",#should be done -> mix variance equality test
                     #"W=",#non-parametric used in literature
                     #"S=",f$statistic,", rho="
                     "rho=",estimate %>% format(digits=2),
                     "\nP",ifelse(p.value<0.001,"<0.001",
                                  paste0("=",p.value %>% format(digits=2)))
                     )
         )
stt <- stt %>% union(j)
}
stt <- stt %>% arrange(igg) %>% dplyr::select(igg,everything()) %>% 
  mutate(x=.1,
         y=55)
# plot
age %>% #filter(igg==levels(f)[1]) %>% 
  ggplot(aes(Ab.units,edad)) +
  geom_point() +
  scale_x_log10() +
  #scale_y_log10() +
  geom_smooth(method = lm,se=F,col="grey50",lwd=.5) +
  #geom_smooth(method = loess,se=F,col="grey50",lwd=.5) +
  geom_text(aes(x,y,label=lab),data = stt,
            vjust=.5,hjust=0.05,size=3.5) +
  facet_grid(~igg
             #,scales = "free"
             ) +
  #facet_wrap(~igg,ncol = 5)
  labs(title="Correlation between AU and parasitemia per IgG subtype")

5.5 Association

  • outcome: symptomatic P.f. malaria

5.5.1 On Power and sample size

5.5.1.1 minimum number of candidate predictors

case=20
ctrl=24
m_c=min(case,ctrl) #limiting sample size
p=5 #current number of predictors
#round(m_c/15) #
p<m_c/15
[1] FALSE
  • Given the current limiting sample size, for a reliable model the number of candidate predictors must be lower than 1.

5.5.1.2 minimum number of cases

k=5 #number of covariates
p= 0.4 # prevalence of outcome
n_x=10*k/p
  • Given the measured covariates and prevalence of modeled outcome, the minimum sample size required is 125.
# exposition: symptomatic malaria (60% asympt in Pf)
#
# given the proportion (prevalence) relevant OR and required power, 
# obtain the sample size required
p=0.40 #proportion of exposure in general population OR outcome provalence
#(OR=pA*(1-pB)/pB/(1-pA)) # 2
OR=.5 #hypothetical OR
#
kappa=1 # sampling ratio between case:control
alpha=0.05 #type 1 error (false positives)
beta=0.20 #power=1-beta #type 2 error (false negatives)
#(n= (((1+kappa)^2)*((qnorm(1-alpha/2)+qnorm(1-beta))^2)) / (kappa*p*(1-p)*((log(OR))^2)) )
n1= (4*((qnorm(1-alpha/2)+qnorm(1-beta))^2)) / (p*(1-p)*((log(OR))^2)) 
#ceiling(n) # Afridi 220, Bragga 263, Stanisic 206, Medeiros 28+24
  • Given the known prevalence of symptomatic malaria in Iquitos and a relevant Odds Ratio reported in literature, a sample size of 273 would be required to achieve a power 80%.
# given the available sample size and obtained Odds Ratio, 
# obtain the actual power
n2= 44
#(OR=.5)
z=log(OR)*sqrt(n2)/sqrt(((1+kappa)^2)/(kappa*p*(1-p)))
Power=pnorm(z-qnorm(1-alpha/2))+pnorm(-z-qnorm(1-alpha/2))
  • Following the same method, given the current sample size, this analysis have a power of 20.32%.

5.5.2 Tidy up

5.5.2.1 inmuno

#library(tidyverse)
mmo <- mco %>% #filter(igg=="igg") %>% 
  mutate(pheno=as.factor(pheno)) %>% 
  mutate(pheno=forcats::fct_relevel(pheno,"symptomatic")) %>% 
  mutate(pheno.num=ifelse(pheno=="asymptomatic",0,1)) %>% 
  mutate(pheno.log=ifelse(pheno=="asymptomatic",FALSE,TRUE))
  • the only reads available for sample 2235 are for the asymptomatic state!
cova %>% 
covb %>% 
covx %>% 
  filter(codigo=="2235" | codigo=="3053" | codigo=="9165" | codigo=="9801") %>% 
  arrange(codigo) #%>% 
  #dplyr::select(codigo,edad,sexo,par,everything())
## add covariates
full_join(mmo,mcv,by=c("ID","par","pheno")) %>% 
  filter(ID=="2235" | ID=="3053" | ID=="9165" | ID=="9801") %>% 
  arrange(ID)

5.5.2.2 covariates

  • NOTA: 2235 tiene dos observaciones en matriz de covariables, pero en templates solo ha sido identificado como asintomático!
mcv_t <- mcv %>% #filter(igg=="igg") %>% 
  mutate(pheno=as.factor(pheno)) %>% 
  mutate(pheno=forcats::fct_relevel(pheno,"symptomatic")) %>% 
  mutate(pheno.num=ifelse(pheno=="asymptomatic",0,1)) %>% 
  mutate(pheno.log=ifelse(pheno=="asymptomatic",FALSE,TRUE))

5.5.2.3 inmuno per subclass

### MULTIPLE LOGISTIC REGRESSION
mmo_x <- mmo %>% 
  dplyr::select(ID,
                #code,
                #pheno,
                igg
                ,Ab.units
                #,Ab.units_log
                ,pheno.num#,pheno.log # 1: symptomatic, 0:: asymptomatic
                ) %>% 
  spread(igg
         ,Ab.units
         #,Ab.units_log
         )
#mmo_x.omit = na.omit(mmo_x)

5.5.2.4 add covariates

mlr <- mcv_t %>% 
  dplyr::select(ID,pheno.num, edad, sexo, par) %>% 
  inner_join(mmo_x,by=c("ID","pheno.num"))
mlr_na = na.omit(mlr)
#dd <- rms::datadist(mlr_na); options(datadist='dd')
# https://stackoverflow.com/questions/7505547/detach-all-packages-while-working-in-r
detachAllPackages <- function() {
  basic.packages <- c("package:stats",
                      "package:graphics",
                      "package:grDevices",
                      "package:utils",
                      "package:datasets",
                      "package:methods",
                      "package:base")
  package.list <- search()[
    ifelse(
      unlist(
        gregexpr("package:",search())
        )==1,TRUE,FALSE
      )
    ]
  package.list <- setdiff(package.list,basic.packages)
  if (length(package.list)>0)  
    for (package in package.list) 
      detach(package, character.only=TRUE)
}
detachAllPackages()
# EXPLAINED: https://stats.stackexchange.com/questions/64788/interpreting-a-logistic-regression-model-with-multiple-predictors
library(tidyverse)
mmo_x_rms <- mlr_na %>% 
  mutate(igg_c=ntile(igg,3),
         igg1_c=ntile(igg1,3),
         igg2_c=ntile(igg2,3),
         igg3_c=ntile(igg3,3),
         igg4_c=ntile(igg4,3)
         ) %>% 
  mutate(igg_c=as.factor(igg_c),
         igg1_c=as.factor(igg1_c),
         igg2_c=as.factor(igg2_c),
         igg3_c=as.factor(igg3_c),
         igg4_c=as.factor(igg4_c)) %>% 
  mutate(igg_d=igg/10,
         igg1_d=igg1/10,
         igg2_d=igg2/10,
         igg3_d=igg3/10,
         igg4_d=igg4/10) %>% 
  mutate(igg_l=log10(igg),
         igg1_l=log10(igg1),
         igg2_l=log10(igg2),
         igg3_l=log10(igg3),
         igg4_l=log10(igg4)) #%>% 
  #dplyr::select(ID,pheno.num,
   #             igg=igg_c,
    #            igg1=igg1_c,
     #           igg2=igg2_c,
      #          igg3=igg3_c,
       #         igg4=igg4_c
        #        )
dd <- rms::datadist(mmo_x_rms); options(datadist='dd')

5.5.2.5 data with missings

mmo %>% dplyr::count(igg)

5.5.3 Univariate

5.5.3.1 PRE: univariate

5.5.3.1.1 age
5.5.3.1.2 sex
5.5.3.1.3 parasitemia
5.5.3.1.4 igg
5.5.3.1.5 igg1
5.5.3.1.6 igg2
5.5.3.1.7 igg3
5.5.3.1.8 igg4
5.5.3.1.9 IgG model
5.5.3.1.10 stepwise selection
5.5.3.1.10.1 selected model

6 References

1. Miura K, Orcutt AC, Muratova OV, Miller LH, Saul A, Long CA. Development and characterization of a standardized ELISA including a reference serum on each plate to detect antibodies induced by experimental malaria vaccines. Vaccine. 2008;26(2):193-200. doi:10.1016/j.vaccine.2007.10.064.

2. Hughes S. Plater: Read, Tidy, and Display Data from Microtiter Plates.; 2016. https://CRAN.R-project.org/package=plater.

3. Wickham H. Readxl: Read Excel Files.; 2016. https://CRAN.R-project.org/package=readxl.

4. Garmonsway D. Tidyxl: Read Untidy Excel Files. https://github.com/nacnudus/tidyxl.

5. Ritz C, Baty F, Streibig JC, Gerhard D. Dose-response analysis using r. Xia Y, ed. PLOS ONE. 2015;10(12):e0146021. doi:10.1371/journal.pone.0146021.

6. Sveidqvist K, Bostock M, Pettitt C, Daines M, Kashcha A, Iannone R. DiagrammeR: Create Graph Diagrams and Flowcharts Using R.; 2016. https://CRAN.R-project.org/package=DiagrammeR.

LS0tCnRpdGxlOiAidW5hcC1yYWZhZWwiCmF1dGhvcjogIkFuZHJlZSBWYWxsZSBDYW1wb3MiCmRhdGU6ICdgciBTeXMuRGF0ZSgpYCcKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgI2h0bWxfZG9jdW1lbnQ6I3BkZl9kb2N1bWVudCAtPiBrZWVwX3RleDogeWVzCiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICB0b2M6IHllcwogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICB0b2NfZGVwdGg6IDUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiB5ZXMKICAgIGNvZGVfZm9sZGluZzogImhpZGUiCiAgICAjZGZfcHJpbnQ6IHBhZ2VkCmJpYmxpb2dyYXBoeTogYW5hbHlzaXMvU2Vyb01hcmtlci5iaWIKYmlibGlvLXN0eWxlOiBhcGFsaWtlCmxpbmstY2l0YXRpb25zOiB5ZXMKY3NsOiBhbmFseXNpcy9hbWVyaWNhbi1tZWRpY2FsLWFzc29jaWF0aW9uLmNzbAotLS0KCjwhLS0KCkhJR0hMSUdUSFMKLSBOaXZlbGVzIGRlIGFudGljdWVycG9zIGRlIElnRyB0b3RhbCBlc3TDoW4gYXNvY2lhZG9zIGEgdW5hIHByb3RlY2Npw7NuIGNvbnRyYSBhIGxhIG1hbGFyaWEgc2ludG9tw6F0aWNhLgotIE5pdmVsZXMgZGUgYW50aWN1ZXJwb3MgZGUgbGEgc3ViY2xhc2UgSWdHMyBwcmVzZW50YW4gbGEgbWF5b3IgYXNvY2lhY2nDs24gYSBsYSBwcmVzZW5jaWEgZGUgbWFsYXJpYSBzaW50b23DoXRpY2EuCi0gQXNpbnRvbcOhdGljb3MgeSBzaW50b23DoXRpY29zIHByZXNlbnRhbiBkaWZlcmVuY2lhcyBlbiBlbCBuaXZlbGVzIHkgcHJvcG9yY2nDs24gZGUgc2Vyb3Bvc2l0aXZvcyBwYXJhIGxhcyBzdWJjbGFzZXMgSWdHMSBlIElnRzMuCgogeSBkZWJpbG1lbnRlIGFzb2NpYWRhIGNvbiBsYSBwcmVzZW5jaWEgZGUgc8OtbnRvbWFzIChJUVItQU9SPSAwLjU4LCA5NSUgQ0k9IDAuMjkg4oCTIDEuMTcpCgogU2luIGVtYmFyZ28sIHNlIGlkZW50aWZpY8OzIHF1ZSBsYSBzdWJjbGFzZSBJZ0czIGVzdHV2byB1bmEgbWF5b3IgYXNvY2lhY2nDs24gY29uIGxhIHByZXNlbmNpYSBkZSBzw61udG9tYXMgKElRUi1BT1I9MS42MSwgOTUlIENJPSAwLjYxIOKAkyA0LjIxKQoKTUFOVVNDUklQVCBOT1RFUzoKCiBPYnR1dmltb3MgcXVlIHBhY2llbnRlcyBhc2ludG9tw6F0aWNvcyBwcmVzZW50YW4gdW5hIG1heW9yIHJlc3B1ZXN0YSBkZSBhbnRpY3VlcnBvcyBJZ0cgcXVlIHBhY2llbnRlcyBzaW50b23DoXRpY29zIChXPSA1MzksIHA8MC4wNSksIGludmVyc2FtZW50ZSBjb3JyZWxhY2lvbmFkYSBhIGxhIGRlbnNpZGFkIGRlIHBhcsOhc2l0b3MgKHJobz0gLTAuNDIsIHA8MC4wMSkgeSBkZWJpbG1lbnRlIGFzb2NpYWRhIGNvbiBsYSBwcmVzZW5jaWEgZGUgc8OtbnRvbWFzIChJUVItT1I9IDAuNDgsIDk1JSBDST0gMC4xOSDigJMgMS4yMSkuIENvbiByZXNwZWN0byBhIGxhcyBzdWJjbGFzZXMsIHNlIG9ic2VydsOzIHVuIG1heW9yIG5pdmVsIGRlIHJlc3B1ZXN0YSB5IHByb3BvcmNpw7NuIGRlIHNlcm9wb3NpdGl2b3MgZW4gSWdHMSBlIElnRzMgc2luIGRpZmVyZW5jaWFzIGVudHJlIHNpbnRvbcOhdGljb3MgeSBhc2ludG9tw6F0aWNvcyAoUD4wLjA1KS4gU2luIGVtYmFyZ28sIHNlIGlkZW50aWZpY8OzIHF1ZSBsYSBzdWJjbGFzZSBJZ0czIGVzdHV2byBhbHRhbWVudGUgYXNvY2lhZGEgYSBsYSBwcmVzZW5jaWEgZGUgc8OtbnRvbWFzIChJUVItT1I9Mi4zNSwgOTUlIENJPSAwLjgwIOKAkyA2Ljg5KS4KCi0gV2UgdXNlZCBhIG11bHRpcGxlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gYW5kIGVzdGltYXRlZCBvZGQgcmF0aW9zIChPUikgZm9yIGVhY2ggSWdHIHN1YmNsYXNzIHRvIGRldGVybWluZWQgdGhlIGFzc29jaWF0aW9uIGJldHdlZW4gdGhlIHN5bXB0b21hdGljIHByb2ZpbGUgYW5kIGludGVuc2l0eSBvZiBhbnRpYm9keSByZXNwb25zZQoKV2UgdmVyaWZpZWQgdGhlIGFzc29jaWF0aW9uIGJldHdlZW4gdGhlIHByZXNlbmNlIG9mIHN5bXB0b21hdGljIG1hbGFyaWEsIGFzIGEgYmluYXJ5IHJlc3BvbnNlLCBhbmQgdGhlIHNldCBvZiB0b3RhbCBJZ0cgYW5kIHN1YmNsYXNzZXMgYXMgY29udGludW9zIHByZWRpY3RvcnMsIHVzaW5nIGFnZSBhbmQgc2V4IGFzIGFkanVzdG1lbnQgY292YXJpYXRlcyBpbiB0aGUgbXVsdGl2YXJpYXRlIGFuYWx5c2lzLiBXZSBwZXJmb3JtZWQgYSBsb2dpc3RpYyByZWdyZXNzaW9uIHdpdGggcGVuYWxpemVkIG1heGltdW0gbGlrZWxpaG9vZCBlc3RpbWF0aW9uCgozLjQuIEFzb2NpYWNpw7NuIGRlIEFVIHkgYXNpbnRvbWF0b2xvZ8OtYQoKLS0+CgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAjZmlnLnBhdGggPSAiMDEtIiwKICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSkKI2tuaXRyOjpvcHRzX2tuaXQkc2V0KHJvb3QuZGlyID0gJy4uLy4nKQoKb3B0aW9ucyh3aWR0aCA9IDYwKSAjIGV4cGFuZCBsaW1pdHMgb2YgQ09OU09MRSBvdXRwdXQKCiNyZXF1aXJlKEhtaXNjKQojbXUgPC0gbWFya3VwU3BlY3MkaHRtbCAgICMgbWFya3VwU3BlY3MgaXMgaW4gSG1pc2MKIyBoaWRkZW4gY29tbWFuZCAoPGNvZGU+ciBtdSR3aWRlc2NyZWVuKCk8L2NvZGU+KSB0byB1c2UgYW4gZW50aXJlIHdpZGUgc2NyZWVuLiAjIG11JHdpZGVzY3JlZW4oKQojYHIgbXUkd2lkZXNjcmVlbigpYApgYGAKCiMgRUxJU0EgU1RBTkRBUkRJWkFUSU9OIHsjc3RkcmFkfQoKIyMgQWltCgoqIFByaW5jaXBhbDogCiAgICAtIEltcGxlbWVudCBhIHJlcHJvZHVjaWJsZSBzdGFuZGFyZGl6YXRpb24gb2YgT0QgdmFsdWVzIGFjcm9zcyBFTElTQSBwbGF0ZXMgZm9sbG93aW5nIAogICAgKipNaXVyYSBldC5hbC4sIDIwMDgqKltATWl1cmEyMDA4XS4KCiogU2Vjb25kYXJ5OiAKICAgIC0gR2VuZXJhdGUgdXNlZnVsIG91dHB1dHMgdG8gY29tcGFyZSBzdGFuZGFyZGl6YXRpb24gcXVhbGl0eS4KCgojIyBUbyBEbwoKLSBXcml0ZSBtZXRob2RzIGZvciB0aGUgbWFudXNjcmlwdC4KCiMjIERlcGVuZGVuY2llcwoKVGhlIHJlcXVpcmVkIFIgcGFja2FnZXMgZm9yIHRoaXMgYW5hbHlzaXMgYXJlOgoKKyBgcGxhdGVyYCBbQHBsYXRlcl0KKyBgcmVhZHhsYCBbQHJlYWR4bF0KKyBgdGlkeXhsYCBbQHRpZHl4bF0KKyBgZHJjYCBbQFJpdHoyMDE1XQoKYGBge3IsIHJlc3VsdHM9J2hpZGUnLCBtZXNzYWdlPUZBTFNFfQojI2Vzc2VudGlhbApsaWJyYXJ5KHRpZHl2ZXJzZSkgICAgIyBzZXQgb2YgdGlkeSBwYWNrYWdlcyAocmVhZHIsIHRpYmJsZSwgZHBseXIsIHRpZHlyLCBnZ3Bsb3QyLCDCv3B1cnI/KQpsaWJyYXJ5KHRpZHl4bCkgICAgICAgIyByZWFkIHVudGlkeSBleGNlbCBmb3JtYXRzCmxpYnJhcnkocmVhZHhsKSAgICAgICAjIHJlYWQgZXhjZWwgZmlsZXMgYXMgdGlkeSB0YWJsZXMKbGlicmFyeShkcmMpICAgICAgICAgICMgZml0IGRvc2UtcmVzcG9uc2UgbW9kZWxzCmxpYnJhcnkobWl4dG9vbHMpICAgICAjIGFuYWx5emUgZmluZXRlIG1peHR1cmUgbW9kZWxzCiMjYWNjZXNvcnkKbGlicmFyeShEaWFncmFtbWVSKSAgICMgY3JlYXRlIGZsb3djaGFydApgYGAKCmBgYHtyfQp0aGVtZV9zZXQodGhlbWVfYncoKSkKYGBgCgoKIyMgTWV0aG9kCgotIHVzaW5nIGBEaWFncmFtbWVSYCBbQERpYWdyYW1tZVJdCgpgYGB7ciwgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9OX0KI2luc3RhbGwucGFja2FnZXMoIkRpYWdyYW1tZVIiKQojbGlicmFyeShEaWFncmFtbWVSKQoKRGlhZ3JhbW1lUigiCiAgZ3JhcGggTFIKICAgIEFbWExTIGRhdGFdIC0uLT4gfHJlYWR4bCt0aWR5eGx8IEJ7UiBkYXRhfQogICAgWltDU1YgZGF0YV0gLS4tPiB8cGxhdGVyfCBCe1IgZGF0YX0KICAgIEIgLS0+IEMxW1NURF0KICAgIEIgLS0+IEVbY3RyICsvLV0KICAgIEIgLS0+IEQxW1VOS10KICAgIAogICAgQzEgLS4tPiB8ZHJjfCBDMls0cExMIG1vZGVsXQogICAgQzIgLS0+IEMzW0JveC1Db3hdCiAgICBDMyAtLT4gRntVTksgQWIudW5pdHN9CgogICAgRDEgLS0+IEQyW21lYW4uT0RdCiAgICBEMiAtLT4gRDNbT0QgJUNWXQogICAgRDMgLS0+IEYKICAgIAogICAgRiAtLT4gRzFbSGlzdG9ncmFtXQogICAgRiAtLT4gRzJbRGVuc2l0eV0KICAgIEYgLS0+IEczW1FRUGxvdF0KCiAgICBzdHlsZSBaIGZpbGw6I2ZmZmZmZiwgc3Ryb2tlOiMwMDAwMDAsIHN0cm9rZS13aWR0aDoycHggICAgCiAgICBzdHlsZSBBIGZpbGw6I2ZmZmZmZiwgc3Ryb2tlOiMwMDAwMDAsIHN0cm9rZS13aWR0aDoycHgKICAgIHN0eWxlIEIgZmlsbDojZmZmZmZmLCBzdHJva2U6IzAwMDAwMCwgc3Ryb2tlLXdpZHRoOjJweAogICAgc3R5bGUgQzEgZmlsbDojZmZmZmZmLCBzdHJva2U6IzAwMDAwMCwgc3Ryb2tlLXdpZHRoOjJweAogICAgc3R5bGUgQzIgZmlsbDojZmZmZmZmLCBzdHJva2U6IzAwMDAwMCwgc3Ryb2tlLXdpZHRoOjJweAogICAgc3R5bGUgQzMgZmlsbDojZmZmZmZmLCBzdHJva2U6IzAwMDAwMCwgc3Ryb2tlLXdpZHRoOjJweAogICAgc3R5bGUgRDEgZmlsbDojZmZmZmZmLCBzdHJva2U6IzAwMDAwMCwgc3Ryb2tlLXdpZHRoOjJweAogICAgc3R5bGUgRDIgZmlsbDojZmZmZmZmLCBzdHJva2U6IzAwMDAwMCwgc3Ryb2tlLXdpZHRoOjJweAogICAgc3R5bGUgRDMgZmlsbDojZmZmZmZmLCBzdHJva2U6IzAwMDAwMCwgc3Ryb2tlLXdpZHRoOjJweAogICAgc3R5bGUgRSBmaWxsOiNmZmZmZmYsIHN0cm9rZTojMDAwMDAwLCBzdHJva2Utd2lkdGg6MnB4CiAgICBzdHlsZSBGIGZpbGw6I2ZmZmZmZiwgc3Ryb2tlOiMwMDAwMDAsIHN0cm9rZS13aWR0aDoycHgKICAgIHN0eWxlIEcxIGZpbGw6I2ZmZmZmZiwgc3Ryb2tlOiMwMDAwMDAsIHN0cm9rZS13aWR0aDoycHgKICAgIHN0eWxlIEcyIGZpbGw6I2ZmZmZmZiwgc3Ryb2tlOiMwMDAwMDAsIHN0cm9rZS13aWR0aDoycHgKICAgIHN0eWxlIEczIGZpbGw6I2ZmZmZmZiwgc3Ryb2tlOiMwMDAwMDAsIHN0cm9rZS13aWR0aDoycHgKIikKYGBgCgojIyMgTG9nLUxvZ2lzdGljICg0cExMKSBtb2RlbAoKVGhlIGN1cnZlIG9mIHRoZSAqKmxvZy1sb2dpc3RpYyBzeW1ldHJpYyoqIG1vZGVsIGRlc2NyaWJlIHRoZSAqcmVzcG9uc2UqIGBmKHgpYCBkZXBlbmRlbnQgb2YgdGhlICpkb3NlKiBgeGAgCmFuZCAqKjA0IHBhcmFtZXRlcnMqKjogJCQgZih4KT1mKHg7YixjLGQsZSk9YytcZnJhY3tkLWN9ezErXGV4cFtiKGxvZyh4KS1sb2coZSkpXX1cICQkIHdoZXJlOiAKICAKLSBgY2AgaXMgdGhlICoqbG93ZXIgbGltaXQqKiBvZiB0aGUgcmVzcG9uc2Ugd2hlbiB0aGUgKmRvc2UqIGB4YCBhcHByb2FjaGVzIGluZmluaXR5LCAKLSBgZGAgaXMgdGhlICoqdXBwZXIgbGltaXQqKiB3aGVuIHRoZSAqZG9zZSogYHhgIGFwcHJvYWNoZXMgemVybywKLSBgYmAgaXMgdGhlICoqc2xvcGUqKiBhcm91bmQgdGhlICoqcG9pbnQgb2YgaW5mbGVjdGlvbioqLCByZXByZXNlbnRlZCBieSAKLSBgZWAgZGVmaW5lZCBhcyAqKmVmZmVjdGl2ZSBkb3NlKiogYW5kIGNvbW1tb25seSBkZW5vdGVkIGFzIFtAUml0ejIwMTVdOgogICAgKyBgRUQ1MGAsIGBFQzUwYCBvciBgSUM1MGAgZm9yIGNvbnRpbnVvdXMgcmVzcG9uc2VzLAogICAgKyBgTEQ1MGAgb3IgYExDNTBgIGZvciBiaW5vbWlhbCByZXNwb25zZXMsIGFuZAogICAgKyAkVF97NTB9JCBmb3IgZXZlbnQtdGltZSByZXNwb25zZXMuCgojIyBQcm9jZWR1cmUKCioqMTIgc3VtbWFyeSBwbG90cyoqIHBlciBFTElTQSBUZW1wbGF0ZToKCi0gKiozeDMgcGxvdHMqKiBvZiBTVEQgYW5kIFVOSyBkaXN0cmlidXRpb24sIHJlc2lkdWFsIHZhcmlhbmNlIGRpc3RyaWJ1dGlvbiwgYW5kIG1vZGVsIHRyYW5zZm9ybWF0aW9uLgotICoqMXgzIHBsb3RzKiogb2YgT0R+NDUwbm1+LCBtZWFuLk9EIGFuZCBBYi51bml0cyBkaXN0cmlidXRpb25zIGJ5IERlbnNpdHkgcGxvdHMuCgpgYGB7cn0KZ2V0d2QoKQpgYGAKCiMjIyBwaGVub3R5cGVzCgpgYGB7cn0KI3ggPC0gdGlkeXhsOjp0aWR5X3hsc3goImRhdGEtcmF3L3Jhdy91bmFwLXRlc2lzL1JBRkFFTC1kYXRhL1RFTVBMQVRFUyBSYWZhZWwueGxzeCIpJGRhdGEkYFRFTVBMQVRFIEVMSVNBIE7CsDFgCnggPC0gdGlkeXhsOjp0aWR5X3hsc3goImRhdGEtcmF3L3Jhdy91bmFwLXRlc2lzL1JBRkFFTC1kYXRhL1RFTVBMQVRFUyBSYWZhZWwueGxzeCIpJGRhdGEKI3N0cih4KQoKeSA8LSB4W1szXV0gJT4lICNpCiAgZmlsdGVyKHJvdyAlaW4lIDIzOjI5LAogICAgICAgICBjb2wgJWluJSAyOjEzKSAlPiUgCiAgZHBseXI6OnNlbGVjdChhZGRyZXNzLHJvdyxjb2wsbnVtZXJpYyxjaGFyYWN0ZXIsbG9jYWxfZm9ybWF0X2lkKSAlPiUgCiAgdW5pdGUoSUQsYygibnVtZXJpYyIsImNoYXJhY3RlciIpKSAlPiUgCiAgbXV0YXRlKElEPSBzdHJpbmdyOjpzdHJfcmVwbGFjZShJRCwiX05BfE5BXyIsICIiKSwKICAgICAgICAgUGxhdGU9IHBhc3RlMCgiTiIsMykpICU+JSAjaQogIGRwbHlyOjpzZWxlY3QoUGxhdGUsZXZlcnl0aGluZygpKSAlPiUgCiAgZmlsdGVyKCFJRCAlaW4lIGMoIkMrIiwiQy0iLCJOQSIsIkJsYW5rIikpICMlPiUgZ3JvdXBfYnkoSUQpICU+JSBzbGljZSgxKSAlPiUgdW5ncm91cCgpCgp5IDwtIHlbRkFMU0UsXQojc3RyKHkpCgpmb3IoaSBpbiAxOmxlbmd0aCh4KSl7CiAgCiAgYSA8LSB4W1tpXV0gJT4lICNpCiAgZmlsdGVyKHJvdyAlaW4lIDIzOjI5LAogICAgICAgICBjb2wgJWluJSAyOjEzKSAlPiUgCiAgZHBseXI6OnNlbGVjdChhZGRyZXNzLHJvdyxjb2wsbnVtZXJpYyxjaGFyYWN0ZXIsbG9jYWxfZm9ybWF0X2lkKSAlPiUgCiAgdW5pdGUoSUQsYygibnVtZXJpYyIsImNoYXJhY3RlciIpKSAlPiUgCiAgbXV0YXRlKElEPSBzdHJpbmdyOjpzdHJfcmVwbGFjZShJRCwiX05BfE5BXyIsICIiKSwKICAgICAgICAgUGxhdGU9IHBhc3RlMCgiTiIsaSkpICU+JSAjaQogIGRwbHlyOjpzZWxlY3QoUGxhdGUsZXZlcnl0aGluZygpKSAlPiUgCiAgZmlsdGVyKCFJRCAlaW4lIGMoIkMrIiwiQy0iLCJOQSIsIkJsYW5rIikpICMlPiUgZ3JvdXBfYnkoSUQpICU+JSBzbGljZSgxKSAlPiUgdW5ncm91cCgpCiAgCiAgeSA8LSB1bmlvbih5LGEpCiAgCn0KCnkgPC0geSAlPiUgYXJyYW5nZShQbGF0ZSxyb3csY29sKQojeSAlPiUgZHBseXI6OmNvdW50KFBsYXRlKQojc3RkLnJhdwpgYGAKCmBgYHtyfQp5IDwtIHkgJT4lCiAgI2RwbHlyOjpjb3VudChJRCkgJT4lIGRwbHlyOjphcnJhbmdlKGRlc2MobikpCiAgI2ZpbHRlcihJRD09MjIzNSkKICAjZmlsdGVyKElEPT0xODU2KQogICNmaWx0ZXIoSUQ9PTM5NDIpCiAgbXV0YXRlKHBoZW5vPWlmZWxzZShsb2NhbF9mb3JtYXRfaWQgJWluJSBjKDIzLDE3LDIwLDE4LDIxLDE5LDIyKSwiYXN5bXB0b21hdGljIiwKICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShsb2NhbF9mb3JtYXRfaWQgJWluJSBjKDY4LDY5LDcwLDcxLDcyLDczLDI0KSwic3ltcHRvbWF0aWMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5BX2NoYXJhY3Rlcl8pCiAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICkgIyU+JSAKICAjZmlsdGVyKElEPT0yMjM1KQogICNmaWx0ZXIocGhlbm89PSJhc3ltcHRvbWF0aWMiKSAjJT4lIGRwbHlyOjpzZWxlY3QoSUQpCiAgI211dGF0ZShwaGVubz1pZmVsc2UoSUQgJWluJSAuICU+JSBmaWx0ZXIocGhlbm89PSJhc3ltcHRvbWF0aWMiKSAlPiUgZHBseXI6OnNlbGVjdChJRCksImFzeW0iLCJzeW0iKSkKCncgPC0geSAlPiUgZmlsdGVyKHBoZW5vPT0iYXN5bXB0b21hdGljIikgJT4lIGRwbHlyOjpzZWxlY3QoSUQpCgpwaGUgPC0geSAlPiUgCiAgbXV0YXRlKHBoZW5vPSBpZmVsc2UoSUQgJWluJSB3JElELCJhc3ltcHRvbWF0aWMiLCJzeW1wdG9tYXRpYyIpKSAlPiUgIyBSRVNQRVRBIHBoZW5vIGRlIFBMQUNBIDEgeSAyICEKICBtdXRhdGUoaWdnPWlmZWxzZShsb2NhbF9mb3JtYXRfaWQgJWluJSBjKDg1KSwiaWdnMSIsCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGxvY2FsX2Zvcm1hdF9pZCAlaW4lIGMoODcpLCJpZ2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGxvY2FsX2Zvcm1hdF9pZCAlaW4lIGMoODgsMjUpLCJpZ2czIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShsb2NhbF9mb3JtYXRfaWQgJWluJSBjKDkwKSwiaWdnNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImlnZyIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICkgJT4lICNncm91cF9ieShJRCxpZ2cpICU+JSBzbGljZSgxKSAlPiUgdW5ncm91cCgpICU+JSAKICBkcGx5cjo6c2VsZWN0KC1sb2NhbF9mb3JtYXRfaWQjLC1hZGRyZXNzLC1yb3csLWNvbAogICAgICAgICApICU+JSAKICBhcnJhbmdlKFBsYXRlLHJvdyxjb2wpICU+JSAKICBtdXRhdGUoUGxhdGU9IGFzLmZhY3RvcihQbGF0ZSkpICU+JSAKICBkcGx5cjo6c2VsZWN0KC1hZGRyZXNzLC1zdGFydHNfd2l0aCgicm93IiksLWNvbCMsLWxvYwogICAgICAgICApICU+JSAKICBtdXRhdGUocGhlbm89aWZlbHNlKFBsYXRlPT0iTjIiIHwgCiAgICAgICAgICAgICAgICAgICAgICAgIFBsYXRlPT0iTjYiIHwgCiAgICAgICAgICAgICAgICAgICAgICAgIFBsYXRlPT0iTjciLAogICAgICAgICAgICAgICAgICAgICAgInN5bXB0b21hdGljIixwaGVubykpICMgUkVTUEVUQVIgcGhlbm8gUE9SIFBMQUNBIChPSk86IG3DoXMgZGUgdW4gcGhlbm8gcG9yIHBhY2llbnRlKQogIAojZmlsdGVyKElEPT0iMzA1MyIpICMgYXN5bXB0IGluIHRlbXBsYXRlIDYgeSA3CiAgI2RwbHlyOjpjb3VudChwaGVubyxpZ2cpCiAgI2RwbHlyOjpjb3VudChpZ2cpCiAgCgojcGhlIyAlPiUgZHBseXI6OmNvdW50KFBsYXRlKQojcGhlICU+JSBncm91cF9ieShQbGF0ZSkgJT4lIHNsaWNlKDEpCgojcGhlICU+JSBkcGx5cjo6Y291bnQoUGxhdGUscGhlbm8saWdnKSAlPiUgYXJyYW5nZShQbGF0ZSkKYGBgCgojIyMgZGF0YQoKYGBge3IsbWVzc2FnZT1GQUxTRX0Kd2Jfc2hlZXQgPC0gcmVhZHhsOjpleGNlbF9zaGVldHMoImRhdGEtcmF3L3Jhdy91bmFwLXRlc2lzL1JBRkFFTC1kYXRhL1RFTVBMQVRFUyBSYWZhZWwueGxzeCIpCgphbGwgPC0gZGF0YV9mcmFtZShJRD1hcy5jaGFyYWN0ZXIoKSwKICAgICAgICAgICAgICAgICAgT0Q9YXMuZG91YmxlKCksCiAgICAgICAgICAgICAgICAgIFBsYXRlPWFzLmNoYXJhY3RlcigpLAogICAgICAgICAgICAgICAgICBUeXBlPWFzLmNoYXJhY3RlcigpLAogICAgICAgICAgICAgICAgICBBYi51bml0PWFzLmRvdWJsZSgpLAogICAgICAgICAgICAgICAgICBvcmRlcj1hcy5pbnRlZ2VyKCkKICAgICAgICAgICAgICAgICAgKQojc3RyKGFsbCkKCiMgMiBHRU5FUkFURSBSIERBVEEuRlJBTUUKZm9yIChqIGluIDE6bGVuZ3RoKHdiX3NoZWV0KSkgewogIAogIHdiX1BmX21haW4gPC0gcmVhZHhsOjpyZWFkX3hsc3goImRhdGEtcmF3L3Jhdy91bmFwLXRlc2lzL1JBRkFFTC1kYXRhL1RFTVBMQVRFUyBSYWZhZWwueGxzeCIsCiAgICAgICAgICAgICAgICAgIHJhbmdlID0gIkEyMTpNMjkiLAogICAgICAgICAgICAgICAgICBzaGVldCA9IGopI2oKCiAgd2JfUGYgPC0gcmVhZHhsOjpyZWFkX3hsc3goImRhdGEtcmF3L3Jhdy91bmFwLXRlc2lzL1JBRkFFTC1kYXRhL1RFTVBMQVRFUyBSYWZhZWwueGxzeCIsCiAgICAgICAgICAgICAgICAgIHJhbmdlID0gIkEzNTpNNDMiLAogICAgICAgICAgICAgICAgICBzaGVldCA9IGopI2oKICAKICBhbGxfcCA8LSB3Yl9QZl9tYWluICU+JSAKICBkcGx5cjo6cmVuYW1lKHJvdz0iWF9fMSIpICU+JSAKICBnYXRoZXIobG9jLElELC1yb3cpICU+JSAKICBtdXRhdGUobG9jPWFzLm51bWVyaWMobG9jKSkgJT4lIAogIGFycmFuZ2Uocm93LGxvYykgJT4lIAogIG11dGF0ZShJRD0gaWZlbHNlKHJvdyA9PSAiSCIgJiBsb2MgPT0gOSwgIkJsYW5rIiwgSUQpKSAlPiUgI0FOT1RBQ0lPTiBBVVNDRU5URSBFTiBURU1QTEFURVMKICBmdWxsX2pvaW4oCiAgICB3Yl9QZiAlPiUgCiAgICAgIGRwbHlyOjpyZW5hbWUocm93PSJYX18xIikgJT4lIAogICAgICBnYXRoZXIobG9jLE9ELC1yb3cpICU+JSAKICAgICAgbXV0YXRlKGxvYz1hcy5udW1lcmljKGxvYykpICU+JSAKICAgICAgYXJyYW5nZShyb3csbG9jKQogICkgJT4lIAogIG11dGF0ZShQbGF0ZT1wYXN0ZTAoIk4iLGopLCNqCiAgICAgICAgIFR5cGU9aWZlbHNlKHJvdz09IkEiIHwgSUQ9PSJCbGFuayIsInN0ZCIsCiAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShJRD09IkMrIiB8IElEPT0iQy0iLCJjdHIiLCJ1bmsiKSksCiAgICAgICAgIEFiLnVuaXQ9aWZlbHNlKHJvdz09IkEiLHN0cmluZ3I6OnN0cl9yZXBsYWNlKElELCJTVEQgMS8oLispIiwiXFwxIiksCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlKElEPT0iQmxhbmsiLCIwIixOQV9jaGFyYWN0ZXJfKSkKICAgICAgICAgKSAlPiUgCiAgbXV0YXRlKEFiLnVuaXQ9YXMubnVtZXJpYyhBYi51bml0KSkgJT4lIAogIG11dGF0ZShBYi51bml0PWlmZWxzZShyb3c9PSJBIixtYXgoQWIudW5pdCxuYS5ybT1UKS9BYi51bml0LEFiLnVuaXQpKSAlPiUgI3NlbGVjdCgtcm93LC1sb2MpCiAgcmVwbGFjZV9uYShsaXN0KElEID0gIm5hIikpICU+JSAKICBmaWx0ZXIoSUQhPSJuYSIpICU+JSAKICBtdXRhdGUob3JkZXI9c2VxKDEsZGltKC4pWzFdKSkgJT4lIAogIGRwbHlyOjpzZWxlY3QoIy1hZGRyZXNzLAogICAgICAgICAtc3RhcnRzX3dpdGgoInJvdyIpLCMtY29sLAogICAgICAgICAtbG9jKQogIAogIGFsbCA8LSB1bmlvbihhbGwsYWxsX3ApCiAgCn0KCmFsbCA8LSBhbGwgJT4lIGFycmFuZ2UoUGxhdGUsb3JkZXIpCiNhbGwgJT4lIGRwbHlyOjpjb3VudChUeXBlKQpgYGAKCmBgYHtyfQoKZmluIDwtIGRhdGFfZnJhbWUoUGxhdGU9YXMuY2hhcmFjdGVyKCksCiAgICAgICAgICAgICAgICAgIG9yZGVyPWFzLmludGVnZXIoKSwKICAgICAgICAgICAgICAgICAgSUQ9YXMuY2hhcmFjdGVyKCksCiAgICAgICAgICAgICAgICAgIFR5cGU9YXMuY2hhcmFjdGVyKCksCiAgICAgICAgICAgICAgICAgIEFiLnVuaXQ9YXMuZG91YmxlKCksCiAgICAgICAgICAgICAgICAgIE9EPWFzLmRvdWJsZSgpLAogICAgICAgICAgICAgICAgICBwaGVubz1hcy5jaGFyYWN0ZXIoKSwKICAgICAgICAgICAgICAgICAgaWdnPWFzLmNoYXJhY3RlcigpCiAgICAgICAgICAgICAgICAgICkKI3N0cihmaW4pCgpmb3IgKGogaW4gMTpsZW5ndGgod2Jfc2hlZXQpKSB7CiAgCiAgZmluX3AgPC0gZnVsbF9qb2luKHBoZSAlPiUgCiAgICAgICAgICAgIGZpbHRlcihQbGF0ZT09bGV2ZWxzKHBoZSRQbGF0ZSlbal0pICU+JSAjcmVxdWlyZXMgagogICAgICAgICAgICBtdXRhdGUob3JkZXI9c2VxKDEzLDEyK2RpbSguKVsxXSkpLAogICAgICAgICAgYWxsICU+JSAKICAgICAgICAgICAgZmlsdGVyKFBsYXRlPT1sZXZlbHMocGhlJFBsYXRlKVtqXSkgJT4lICNyZXF1aXJlcyBqCiAgICAgICAgICAgIGZpbHRlcihUeXBlPT0idW5rIikgJT4lIAogICAgICAgICAgICBkcGx5cjo6c2VsZWN0KC1QbGF0ZSwtSUQpLAogICAgICAgICAgYnk9Im9yZGVyIikgJT4lIAogICAgZHBseXI6OnNlbGVjdChQbGF0ZSxvcmRlcixJRCxUeXBlLEFiLnVuaXQsT0QscGhlbm8saWdnKQogIAogIGZpbiA8LSB1bmlvbihmaW4sZmluX3ApCiAgCn0KCmZpbiA8LSBmaW4gJT4lIGFycmFuZ2UoUGxhdGUsb3JkZXIpCiNmaW4gIyU+JSBmaWx0ZXIoSUQ9PTMwNTMpCgojT0pPISEhISBNQUxBIEFOT1RBQ0nDk04KI2ZpbiAlPiUgZmlsdGVyKFBsYXRlPT0iTjIiKSAlPiUgZHBseXI6OmNvdW50KHBoZW5vKQojZmluICU+JSBmaWx0ZXIoUGxhdGU9PSJOMiIpICU+JSBmaWx0ZXIocGhlbm89PSJhc3ltcHRvbWF0aWMiKQojZmluICU+JSBkcGx5cjo6Y291bnQoUGxhdGUpCgplbmQgPC0gZmluICU+JSAKICB1bmlvbihhbGwgJT4lIAogICAgICAgICAgZmlsdGVyKFR5cGUhPSJ1bmsiKSAlPiUgCiAgICAgICAgICBkcGx5cjo6c2VsZWN0KFBsYXRlLElELFR5cGUsQWIudW5pdCxPRCxvcmRlcikgJT4lIAogICAgICAgICAgbXV0YXRlKHBoZW5vPU5BX2NoYXJhY3Rlcl8sCiAgICAgICAgICAgICAgICAgaWdnPU5BX2NoYXJhY3Rlcl8pCiAgICAgICAgKSAlPiUgCiAgYXJyYW5nZShQbGF0ZSxvcmRlcikgJT4lIAogIGRwbHlyOjpzZWxlY3QoLW9yZGVyKQoKI2VuZCAjJT4lIGZpbHRlcihJRD09MjIzNSkKYGBgCgpgYGB7cixldmFsPUZBTFNFLGVjaG89RkFMU0V9CiNlbmQgJT4lIGZpbHRlcihUeXBlPT0idW5rIikgJT4lIGRwbHlyOjpjb3VudChQbGF0ZSxJRCxwaGVubyxpZ2cpICU+JSBhcnJhbmdlKElELG4pCiNlbmQgJT4lIGZpbHRlcihUeXBlPT0idW5rIikgJT4lIGRwbHlyOjpjb3VudChQbGF0ZSxwaGVubyxpZ2cpICMlPiUgYXJyYW5nZShJRCxuKQojZW5kICU+JSBmaWx0ZXIoUGxhdGU9PSJONSIpCiNlbmQgJT4lIGZpbHRlcihQbGF0ZT09Ik42IiAmIHBoZW5vPT0iYXN5bXB0b21hdGljIikgJT4lIGFycmFuZ2UoSUQpCiNlbmQgJT4lIGZpbHRlcihQbGF0ZT09Ik43IiAmIHBoZW5vPT0iYXN5bXB0b21hdGljIikgJT4lIGFycmFuZ2UoSUQpCiNlbmQgJT4lIGZpbHRlcihJRD09IjMwNTMiIHwgSUQ9PSI5MTY1IikgJT4lIGFycmFuZ2UoSUQpCiNlbmQgJT4lIGZpbHRlcihJRD09Ijk4MDEiKSAlPiUgYXJyYW5nZShJRCkKI2VuZCAlPiUgZmlsdGVyKFBsYXRlPT0iTjIiICYgcGhlbm89PSJhc3ltcHRvbWF0aWMiKSAlPiUgYXJyYW5nZShJRCkKZW5kICU+JSBmaWx0ZXIoSUQ9PSIzMDUzIiB8IElEPT0iOTE2NSIgfCBJRD09Ijk4MDEiKSAlPiUgYXJyYW5nZShJRCkKYGBgCgojIyMgc3RhbmRhcml6YXRpb24KCmBgYHtyfQojIG1vZCBpcyBtZWFuICBvZCAocGx1cyBzZCBhbmQgY3YpCm1vZCA8LSBlbmQgJT4lIAogIGZpbHRlcihUeXBlPT0idW5rIikgJT4lIAogIGdyb3VwX2J5KFBsYXRlLGlnZyxJRCkgJT4lIAogIHN1bW1hcmlzZV9hdCh2YXJzKE9EKSxjKCJtZWFuIiwic2QiKSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgZHBseXI6OnJlbmFtZShtZWFuLk9EPSJtZWFuIiwKICAgICAgICAgICAgICAgIHNkLk9EPSJzZCIpICU+JSAKICBtdXRhdGUoY3YuT0Q9MTAwKnNkLk9EL21lYW4uT0QpICU+JSAKICBtdXRhdGUob3JkZXI9c2VxKDEsZGltKC4pWzFdKSkKICAjZmlsdGVyKElEPT0iMTU3MCIpCgptYWIgPC0gZW5kICU+JSAKICBmaWx0ZXIoVHlwZT09InVuayIpICU+JSAKICBncm91cF9ieShQbGF0ZSxpZ2csSUQpICU+JSAKICBzbGljZSgxKSAlPiUgCiAgdW5ncm91cCgpICU+JSAjZmlsdGVyKElEPT0iMTU3MCIpCiAgbXV0YXRlKG9yZGVyPXNlcSgxLGRpbSguKVsxXSkpICU+JSAKICBmdWxsX2pvaW4obW9kICU+JSBkcGx5cjo6c2VsZWN0KG9yZGVyLG1lYW4uT0Qsc2QuT0QsY3YuT0QpLAogICAgICAgICAgICBieT0ib3JkZXIiKSAlPiUgI211dGF0ZSh0ZXN0LmlkPSBJRC54PT1JRC55KSAlPiUgZHBseXI6OmNvdW50KHRlc3QuaWQpCiAgZHBseXI6OnNlbGVjdCgtb3JkZXIsLU9EKSAlPiUgCiAgbXV0YXRlKG9yZD1zZXEoMSxkaW0oLilbMV0pKSAlPiUgCiAgdW5pdGUoY29kZSxJRCxvcmQsc2VwPSJfIixyZW1vdmUgPSBGKQpgYGAKCmBgYHtyLGV2YWw9RkFMU0UsIGVjaG89RkFMU0V9CiNtYWIgJT4lIGRwbHlyOjpjb3VudChQbGF0ZSxwaGVubyxpZ2cpCiNtYWIgJT4lIGRwbHlyOjpjb3VudChQbGF0ZSxJRCxwaGVubyxpZ2cpCgptYWIgJT4lIGZpbHRlcigjSUQ9PSIyMjM1IiB8IAogICAgICAgICAgICAgICAgIElEPT0iMzA1MyIgfCBJRD09IjkxNjUiIHwgSUQ9PSI5ODAxIikgJT4lIGFycmFuZ2UoSUQpCmBgYAoKCiMjIyMgYmxhbmsgaXNzdWUKCmBgYHtyfQojbWFzY2FyYQpibGsgPC0gZW5kICU+JSAKICBmaWx0ZXIoSUQ9PSJCbGFuayIpICU+JSAKICBncm91cF9ieShQbGF0ZSkgJT4lIHNsaWNlKDEpICU+JSB1bmdyb3VwKCkgJT4lIAogIGRwbHlyOjpzZWxlY3QoLU9EKQojbWVkaWEgcG9yIHBhciBkZSBibGFuY29zIHBvciBwbGFjYQpzdGQgPC0gZW5kICU+JSAKICBmaWx0ZXIoSUQ9PSJCbGFuayIpICU+JSAKICBncm91cF9ieShQbGF0ZSkgJT4lIAogIHN1bW1hcmlzZV9hdCh2YXJzKE9EKSxtZWFuLG5hLnJtPVQpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogICNkcGx5cjo6cmVuYW1lKG1lYW4uT0Q9Ik9EIikgJT4lIAogIGZ1bGxfam9pbihibGssYnk9IlBsYXRlIikgJT4lIAogIGRwbHlyOjpzZWxlY3QoUGxhdGUsSUQsVHlwZSxBYi51bml0LE9ELGV2ZXJ5dGhpbmcoKSkgJT4lIAogIHVuaW9uKGVuZCAlPiUgZmlsdGVyKFR5cGU9PSJzdGQiICYgSUQhPSJCbGFuayIpKSAlPiUgCiAgYXJyYW5nZShQbGF0ZSxBYi51bml0KSAlPiUgCiAgbXV0YXRlKFBsYXRlPWFzLmZhY3RvcihQbGF0ZSkpCmBgYAoKIyMjIyA0cGxsIHBlciB0ZW1wbGF0ZQoKYGBge3IsbWVzc2FnZT1GQUxTRX0KCm1hYl9pciA8LSBOVUxMCm1vZF9ieCA8LSBOVUxMCgojCiMgbmV3IGRvc2UgbGV2ZWxzIGFzIHN1cHBvcnQgZm9yIHRoZSBsaW5lCiNtZG8kQWIudW5pdHMgJT4lIHN1bW1hcnkoKQpuZXdfeCA8LSBleHBhbmQuZ3JpZChleHAoc2VxKGxvZygwLjEpLGxvZygyMDQ4KSxsZW5ndGg9MTAwKSkpCiMgZGIgdG8gYWRkIHByZWRpY3Rpb25zIG9mIGFsbCBwbGF0ZXMKbmV3IDwtIGRhdGFfZnJhbWUob3JkPWFzLmNoYXJhY3RlcigpLAogICAgICAgICAgICAgICAgICByZXNwPWFzLmRvdWJsZSgpLAogICAgICAgICAgICAgICAgICBwPWFzLmRvdWJsZSgpLAogICAgICAgICAgICAgICAgICBwbWluPWFzLmRvdWJsZSgpLAogICAgICAgICAgICAgICAgICBwbWF4PWFzLmRvdWJsZSgpLAogICAgICAgICAgICAgICAgICBQbGF0ZT1hcy5jaGFyYWN0ZXIoKSkKIwoKZm9yIChqIGluIDE6bGVuZ3RoKGxldmVscyhwaGUkUGxhdGUpKSkgewogIAojCiMgNSBQQVJBTUVURVIgRVNUSU1BVElPTiA0cExMIG1vZGVsCiMKd2IubTEgPC0gZHJtKE9EIH4gQWIudW5pdCwgUGxhdGUsIAogICAgICAgICAgICAgICBkYXRhPSBzdGQgJT4lIGZpbHRlcihQbGF0ZT09bGV2ZWxzKHBoZSRQbGF0ZSlbal0pLCNqCiAgICAgICAgICAgICAjZGF0YT0gc3RkLAogICAgICAgICAgICAgICBmY3QgPSBMTC40KG5hbWVzID0gYygiYiIsICJjIiwgImQiLCAiZSIpKSkKIwp3Yi5tb2RlbCA8LSB3Yi5tMQojIDYgQk9YLUNPWCBUUkFOU0ZPUk1BVElPTiBhZ2FpbnN0IFJFU0lEVUFMIGhldGVyb2dlbmVpdHkKd2IubW9kZWwuQlggPC0gYm94Y294KHdiLm1vZGVsLCAKICAgICAgICAgICAgICAgICAgICAgbWFpbj1leHByZXNzaW9uKCJPcHRpbWFsICIgfiBsYW1iZGEgfiAiIHdpdGggY29uZmlkZW5jZSBpbnRlcnZhbHMiKSwgCiAgICAgICAgICAgICAgICAgICAgIHBsb3RpdCA9IEZBTFNFKQojY29lZmZpY2llbnRzKHdiLm1vZGVsLkJYKSAlPiUgbWF0cml4KDcsNCkKbWFiX3AgPC0gbWFiICU+JSBhcy5kYXRhLmZyYW1lKCkKIyA3IFVOSyBBQi5VTklUUyBFU1RJTUFUSU9OIGJ5IElOVkVSU0UgUkVHUkVTU0lPTgptaXIgPC0gRUQod2IubW9kZWwuQlgsIAogICAgICAgICAgICAgICAgIG1hYl9wW21hYl9wJFBsYXRlPT1sZXZlbHMocGhlJFBsYXRlKVtqXSwibWVhbi5PRCJdLCNqCiAgICAgICAgICAgICAgICAgICAjd2JfTUVBTlsxOm4sNV0sCiAgICAgICAgICAgICAgICAgICB0eXBlID0gImFic29sdXRlIixpbnRlcnZhbCA9ICJkZWx0YSIsCiAgICAgICAgICAgICAgICAgICAjY2xldmVsID0gIlBmYWwiLCAKICAgICAgICAgICAgICAgICBkaXNwbGF5ID0gRkFMU0UpCiAgCm1hYl9pciA8LSByYmluZChtYWJfaXIsbWlyKQptb2RfYnggPC0gcmJpbmQobW9kX2J4LGNvZWZmaWNpZW50cyh3Yi5tb2RlbC5CWCkpCgojCiMgcHJlZGljdGlvbnMgYW5kIGNvbmZpZGVuY2UgaW50ZXJ2YWxzCnBkbSA8LSBwcmVkaWN0KHdiLm1vZGVsLkJYLCBuZXdkYXRhID0gbmV3X3gsIGludGVydmFsID0gImNvbmZpZGVuY2UiKQojIG5ldyBkYXRhIHdpdGggcHJlZGljdGlvbnMKbmV3X3AgPC0gYmluZF9jb2xzKG5ld194ICU+JSAKICAgICAgICAgICAgICAgICAgICAgYXMudGliYmxlKCkgJT4lIAogICAgICAgICAgICAgICAgICAgICByb3duYW1lc190b19jb2x1bW4odmFyID0gIm9yZCIpCiAgICAgICAgICAgICAgICAgICAsIHBkbSAlPiUgCiAgICAgICAgICAgICAgICAgICAgIGFzLnRpYmJsZSgpICU+JSAKICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJvcmQiKQogICAgICAgICAgICAgICAgICAgKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1vcmQxKSAlPiUgCiAgbXV0YXRlKFBsYXRlPWxldmVscyhwaGUkUGxhdGUpW2pdKSAlPiUgCiAgZHBseXI6OnJlbmFtZShyZXNwPVZhcjEscD1QcmVkaWN0aW9uLHBtaW49TG93ZXIscG1heD1VcHBlcikKCm5ldyA8LSB1bmlvbihuZXcsbmV3X3ApCiMKCn0KCiNtYWIKI21hYlttYWIkUGxhdGU9PWxldmVscyhwaGUkUGxhdGUpWzFdLF0gIyU+JSBkdXBsaWNhdGVkKCkgJT4lIHN1bSgpCgojIDcuMSBGRUVEIFVOSyBBQi5VTklUUyBEQVRBLkZSQU1FCm1kbyA8LSBtYWJfaXIgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCkgJT4lIAogICNkcGx5cjo6cmVuYW1lKG9yZD1yb3duYW1lKSAlPiUgCiAgc2VwYXJhdGUocm93bmFtZSxjKCJwYXIiLCJQbGF0ZSIsIm1lYW4uT0QuYyIpLHNlcCA9ICI6IikgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigib3JkIikgJT4lIAogICNtdXRhdGUob3JkPXNlcSgxLGRpbSguKVsxXSkpICU+JSAKICBmdWxsX2pvaW4obWFiICU+JSAKICAgICAgICAgICAgICBtdXRhdGUob3JkPWFzLmNoYXJhY3RlcihvcmQpKSAlPiUgCiAgICAgICAgICAgICAgbXV0YXRlKG1lYW4uT0QuYz1hcy5jaGFyYWN0ZXIobWVhbi5PRCkpCiAgICAgICAgICAgICwKICAgICAgICAgICAgYnkgPSBjKCJvcmQiLCJQbGF0ZSIsIm1lYW4uT0QuYyIpKSAlPiUgCiAgZHBseXI6OnNlbGVjdChQbGF0ZSxvcmQsSUQsY29kZSxUeXBlLHBoZW5vLGlnZyxtZWFuLk9ELHNkLk9ELGN2Lk9ELEFiLnVuaXRzPUVzdGltYXRlLAogICAgICAgICBldmVyeXRoaW5nKCksLXBhciwtbWVhbi5PRC5jLC1BYi51bml0KSAlPiUgCiAgZmlsdGVyKCFjb2RlPT0iMjIzNV8xMzciKSAjIE1BTlVBTCBGSUxURVJJTkcgb2YgcmVwbGljYXRlIG9uIGRpZmZlcmVudCB0ZW1wbGF0ZXMKCm1vZF9idCA8LSBtb2RfYnggJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCkgJT4lIGFzLnRpYmJsZSgpICU+JSAKICBkcGx5cjo6cmVuYW1lKFBsYXRlPXJvd25hbWUpICU+JSAKICBtdXRhdGUoUGxhdGU9c3RyaW5ncjo6c3RyX3JlcGxhY2UoUGxhdGUsIihcXGQpIiwiTlxcMSIpKQoKbmV3IDwtIG5ldyAlPiUgbXV0YXRlKG9yZD1hcy5udW1lcmljKG9yZCkpICU+JSBhcnJhbmdlKFBsYXRlLG9yZCkKYGBgCgojIyMjIG91dHB1dHMKCmBgYHtyfQojCiNmaW4KI2VuZAojbW9kCiNtYWIKCiMgc3RhbmRhcmQgY3VydmUgZGF0YQpzdGQKCiMgZXN0aW1hdGVkIGFiIHVuaXQgZGF0YQptZG8KCiMgZXN0aW1hdGVkIHBhcmFtZXRlcnMgcGVyIHN0YW5kYXJkIGN1cnZlCm1vZF9idAoKIyBwcmVkaWN0ZWQgbW9kZWwgcGVyIHN0YW5kYXJkIGN1cnZlIApuZXcKYGBgCgpgYGB7cixldmFsPUZBTFNFLGVjaG89RkFMU0V9Cm1kbyAlPiUgYXJyYW5nZShJRCxQbGF0ZSkKbWRvICU+JSBncm91cF9ieShJRCkgJT4lICBkcGx5cjo6Y291bnQoKSAlPiUgYXJyYW5nZShkZXNjKG4pKQptZG8gJT4lIGZpbHRlcihJRD09IjMwNTMiIHwgSUQ9PSI5MTY1IiB8IElEPT0iOTgwMSIpICU+JSBhcnJhbmdlKElEKQojbWRvICU+JSBmaWx0ZXIoSUQ9PSIyMjM1IiB8IElEPT0iMTUyNCIgfCBJRD09IjE4NDMiKSAlPiUgYXJyYW5nZShkZXNjKElEKSkKZW5kICU+JSBmaWx0ZXIoSUQ9PSIyMjM1IikgJT4lIGdyb3VwX2J5KFBsYXRlKSAlPiUgZHBseXI6OmNvdW50KHBoZW5vLGlnZykgI1RJRU5FIFJFUExJQ0EgRU4gT1RSTyBURU1QTEFURSEhCm1kbyAlPiUgZmlsdGVyKElEPT0iMjIzNSIpICMgZGF0YSBmaWx0ZXJlZApgYGAKCiMjIyBxdWFsaXR5IGNvbnRyb2wgcGxvdHMKCmBgYHtyfQojc3RkCmN0ciA8LSBlbmQgJT4lIGZpbHRlcihUeXBlPT0iY3RyIikKI2N0ciAlPiUgZmlsdGVyKFBsYXRlPT1sZXZlbHMocGhlJFBsYXRlKVsxXSAmIElEPT0iQysiKSAlPiUgLiRPRAojc3RkICU+JSBmaWx0ZXIoUGxhdGU9PWxldmVscyhwaGUkUGxhdGUpWzFdICYgSUQ9PSJCbGFuayIpICU+JSAuJE9ECmBgYAoKIyMjIyBjdgoKYGBge3IsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTh9Cm1kbyAlPiUgCiAgZ2dwbG90KGFlcyhtZWFuLk9ELGN2Lk9ELGNvbG91cj1QbGF0ZSkpICsKICBnZW9tX3BvaW50KCkgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLDEwMCkpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0PTIwKSxsaW5ldHlwZT0iZGFzaGVkIixzaXplPTAuMykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9MC4yNSksbGluZXR5cGU9ImRhc2hlZCIsc2l6ZT0wLjMpICsKICBmYWNldF93cmFwKH5QbGF0ZSxuY29sID0gNCkgKwogIGxhYnModGl0bGU9IlFDIHBsb3Q6IEludHJhLXBsYXRlIGNvZWZmaWNpZW50IG9mIHZhcmlhdGlvbiIpCmBgYAoKIyMjIyA0cGxsCgpgYGB7ciwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9OH0Kc3RkICU+JSAKICBtdXRhdGUoQWIudW5pdD1pZmVsc2UoQWIudW5pdD09MCwwLjUsQWIudW5pdCkpICU+JSAKICBnZ3Bsb3QoYWVzKEFiLnVuaXQsT0QpKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdD1PRCxsaW5ldHlwZT1JRCksZGF0YT1jdHIpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXI9UGxhdGUpKSArCiAgZ2VvbV9yaWJib24oZGF0YT1uZXcsIGFlcyh4PXJlc3AsIHk9cCwgeW1pbj1wbWluLCB5bWF4PXBtYXgpLCBhbHBoYT0wLjIpICsKICBnZW9tX2xpbmUoZGF0YT1uZXcsIGFlcyh4PXJlc3AsIHk9cCwgY29sb3VyPVBsYXRlKSkgKwogICNjb29yZF90cmFucyh4PSJsb2ciKSArCiAgc2NhbGVfeF9sb2cxMCgpICsKICAjdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKwogIGZhY2V0X3dyYXAoflBsYXRlLG5jb2wgPSA0KSArCiAgbGFicyh0aXRsZT0iUUMgcGxvdDogNC1wYXJhbWV0ZXIgbG9nLWxvZ2lzdGljIG1vZGVsIHBlciBwbGF0ZSIpCiAgI3hsYWIoIkZlcnVsaWMgYWNpZCAobU0pIikgKyB5bGFiKCJSb290IGxlbmd0aCAoY20pIikKYGBgCgpgYGB7cixldmFsPUZBTFNFfQpzdGQgJT4lIAogIGdncGxvdChhZXMoQWIudW5pdCxPRCxjb2xvdXI9UGxhdGUpKSArCiAgZ2VvbV9wb2ludCgpICsKICBmYWNldF93cmFwKH5QbGF0ZSkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9NiwgZXZhbD1GQUxTRX0Kc3RkICU+JSAKICBnZ3Bsb3QoYWVzKGxvZzEwKEFiLnVuaXQpLE9ELGNvbG91cj1QbGF0ZSkpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0PU9ELGxpbmV0eXBlPUlEKSxjdHIsc2l6ZT0wLjMpICsKICBnZW9tX3BvaW50KCkgKwogIGZhY2V0X3dyYXAoflBsYXRlKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD04fQptZG8gJT4lIAogIGdncGxvdChhZXMoQWIudW5pdHMsbWVhbi5PRCxjb2xvdXI9aWdnKSkgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLDEpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2Vycm9yYmFyaChhZXMoeG1pbj1Mb3dlcix4bWF4PVVwcGVyKSwgY29sb3VyPSJibGFjayIsIHNpemU9LjIpICsKICBzY2FsZV94X2xvZzEwKCkgKwogIGZhY2V0X3dyYXAoflBsYXRlK3BoZW5vLG5yb3cgPSAyKSArIAogIGxhYnModGl0bGU9IkVzdGltYXRlcyBvZiBhbnRpYm9keSB1bml0cyAoQVUpIHBlciBwbGF0ZSBhbmQgcGhlbm90eXBlIikKICAjIGludmVyc2UgcmVncmVzc2lvbiBtZXRob2QKICAjZmFjZXRfd3JhcChpZ2d+cGhlbm8sbnJvdyA9IDIpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTgsZXZhbD1GQUxTRSxlY2hvPUZBTFNFfQojIyMjIHNlCm1kbyAlPiUgCiAgbXV0YXRlKHN0ZF9lcnJvcj1VcHBlci1Mb3dlcikgJT4lIAogIGdncGxvdDI6OmdncGxvdChhZXMoc3RkX2Vycm9yLEFiLnVuaXRzLCBjb2xvdXI9UGxhdGUpKSArCiAgZ2VvbV9wb2ludChhbHBoYT0wLjUpICsKICAjZ2VvbV9oaXN0b2dyYW0oI2JpbndpZHRoID0gMTAwLAogICAgICAgICAgICAgICAgICNicmVha3M9c2VxKDAsIDM1MDAsIGJ5ID0gMTAwKQogICAgICAgICAgICAgICAgICNwb3NpdGlvbiA9ICJmaWxsIgogICAgICAgICAgICAgICAgICMpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxMDAwLCAjbHdkPTIsI2NvbCA9ICJyZWQiLCAKICAgICAgICAgICAgIGx0eT0zKSArCiAgZmFjZXRfd3JhcCh+UGxhdGUrcGhlbm8KICAgICAgICAgICAgICxucm93ID0gMiMsc2NhbGVzID0gImZyZWUiCiAgICAgICAgICAgICApICsgCiAgI3NjYWxlX3hfbG9nMTAoKSArCiAgI3NjYWxlX3lfbG9nMTAoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKwogIGxhYnModGl0bGU9IlN0YW5kYXJkIGVycm9ycyBvZiBhbnRpYm9keSB1bml0cyAoQVUpIHBlciBwbGF0ZSBhbmQgcGhlbm90eXBlIikKYGBgCgojIyMgZGlzdHJpYnV0aW9uIHBsb3RzCgojIyMjIGxpbmVhcgoKIyMjIyMgc2NhbGUgZml4CgpgYGB7cixmaWcud2lkdGg9MTAsZmlnLmhlaWdodD00fQojIyMjIyBhYiB1bml0cwphIDwtIG1kbyAlPiUgCiAgZ2dwbG90KGFlcyh4PUFiLnVuaXRzLGZpbGw9cGhlbm8pKSArIHRoZW1lX2J3KCkgIysKICAjc2NhbGVfeF9sb2cxMCgpCgpiIDwtIGEgKwogIGdlb21faGlzdG9ncmFtKGFscGhhPS41LHBvc2l0aW9uID0gImlkZW50aXR5IikgKyBmYWNldF9ncmlkKH5pZ2cpCiNnZ3NhdmUoImRhdGEtcmF3L3Jhdy91bmFwLXRlc2lzL1JBRkFFTC1kYXRhL2FiX2hpc3QucG5nIikKCmMgPC0gYSArIAogIGdlb21fZGVuc2l0eShhbHBoYT0uNSxwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsgZmFjZXRfZ3JpZCh+aWdnKQojZ2dzYXZlKCJkYXRhLXJhdy9yYXcvdW5hcC10ZXNpcy9SQUZBRUwtZGF0YS9hYl9kZW5zLnBuZyIpCiAgI2ZhY2V0X3dyYXAodHJhbnNmb3Jtfm1lYXN1cmUsc2NhbGVzID0gImZyZWUiKQoKUm1pc2M6Om11bHRpcGxvdChiLGMsY29scyA9IDEpCmBgYAoKCiMjIyMjIHNjYWxlIGZyZWUKCmBgYHtyLGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTR9CiMjIyMjIGFiIHVuaXRzCmEgPC0gbWRvICU+JSAKICBnZ3Bsb3QoYWVzKHg9QWIudW5pdHMsZmlsbD1waGVubykpICsgdGhlbWVfYncoKSAjKwogICNzY2FsZV94X2xvZzEwKCkKCmIgPC0gYSArCiAgZ2VvbV9oaXN0b2dyYW0oYWxwaGE9LjUscG9zaXRpb24gPSAiaWRlbnRpdHkiKSArIAogIGZhY2V0X3dyYXAofmlnZywgc2NhbGU9ICJmcmVlIiwgbmNvbCA9IDUpCiNnZ3NhdmUoImRhdGEtcmF3L3Jhdy91bmFwLXRlc2lzL1JBRkFFTC1kYXRhL2FiX2hpc3QucG5nIikKCmMgPC0gYSArIAogIGdlb21fZGVuc2l0eShhbHBoYT0uNSxwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsgCiAgZmFjZXRfd3JhcCh+aWdnLCBzY2FsZT0gImZyZWUiLCBuY29sID0gNSkKI2dnc2F2ZSgiZGF0YS1yYXcvcmF3L3VuYXAtdGVzaXMvUkFGQUVMLWRhdGEvYWJfZGVucy5wbmciKQogICNmYWNldF93cmFwKHRyYW5zZm9ybX5tZWFzdXJlLHNjYWxlcyA9ICJmcmVlIikKClJtaXNjOjptdWx0aXBsb3QoYixjLGNvbHMgPSAxKQpgYGAKCgpgYGB7cixmaWcud2lkdGg9MTAsZmlnLmhlaWdodD00LGV2YWw9RkFMU0V9CiMjIyMjIG9kCmEgPC0gbWRvICU+JSAKICBnZ3Bsb3QoYWVzKHg9bWVhbi5PRCxmaWxsPXBoZW5vKSkgKyB0aGVtZV9idygpICMrCiAgI3NjYWxlX3hfbG9nMTAoKQoKYiA8LSBhICsKICBnZW9tX2hpc3RvZ3JhbShhbHBoYT0uNSxwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsgZmFjZXRfZ3JpZCh+aWdnKQojZ2dzYXZlKCJkYXRhLXJhdy9yYXcvdW5hcC10ZXNpcy9SQUZBRUwtZGF0YS9vZF9oaXN0LnBuZyIpCgpjIDwtIGEgKyAKICBnZW9tX2RlbnNpdHkoYWxwaGE9LjUscG9zaXRpb24gPSAiaWRlbnRpdHkiKSArIGZhY2V0X2dyaWQofmlnZykKI2dnc2F2ZSgiZGF0YS1yYXcvcmF3L3VuYXAtdGVzaXMvUkFGQUVMLWRhdGEvb2RfZGVucy5wbmciKQogICNmYWNldF93cmFwKHRyYW5zZm9ybX5tZWFzdXJlLHNjYWxlcyA9ICJmcmVlIikKClJtaXNjOjptdWx0aXBsb3QoYixjLGNvbHMgPSAxKQpgYGAKCiMjIyMgbG9nCgojIyMjIyBzY2FsZSBmaXgKCmBgYHtyLGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTR9CiMjIyMjIGFiIHVuaXRzCmEgPC0gbWRvICU+JSAKICBnZ3Bsb3QoYWVzKHg9QWIudW5pdHMsZmlsbD1waGVubykpICsgdGhlbWVfYncoKSArCiAgc2NhbGVfeF9sb2cxMCgpCgpiIDwtIGEgKwogIGdlb21faGlzdG9ncmFtKGFscGhhPS41LHBvc2l0aW9uID0gImlkZW50aXR5IikgKyBmYWNldF9ncmlkKH5pZ2cpCiNnZ3NhdmUoImRhdGEtcmF3L3Jhdy91bmFwLXRlc2lzL1JBRkFFTC1kYXRhL2FiX2hpc3QucG5nIikKCmMgPC0gYSArIAogIGdlb21fZGVuc2l0eShhbHBoYT0uNSxwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsgZmFjZXRfZ3JpZCh+aWdnKQojZ2dzYXZlKCJkYXRhLXJhdy9yYXcvdW5hcC10ZXNpcy9SQUZBRUwtZGF0YS9hYl9kZW5zLnBuZyIpCiAgI2ZhY2V0X3dyYXAodHJhbnNmb3Jtfm1lYXN1cmUsc2NhbGVzID0gImZyZWUiKQoKUm1pc2M6Om11bHRpcGxvdChiLGMsY29scyA9IDEpCmBgYAoKIyMjIyMgc2NhbGUgZnJlZQoKYGBge3IsZmlnLndpZHRoPTEwLGZpZy5oZWlnaHQ9NH0KIyMjIyMgYWIgdW5pdHMKYSA8LSBtZG8gJT4lIAogIGdncGxvdChhZXMoeD1BYi51bml0cyxmaWxsPXBoZW5vKSkgKyB0aGVtZV9idygpICsKICBzY2FsZV94X2xvZzEwKCkKCmIgPC0gYSArCiAgZ2VvbV9oaXN0b2dyYW0oYWxwaGE9LjUscG9zaXRpb24gPSAiaWRlbnRpdHkiKSArIAogIGZhY2V0X3dyYXAofmlnZywgc2NhbGU9ICJmcmVlIiwgbmNvbCA9IDUpCiNnZ3NhdmUoImRhdGEtcmF3L3Jhdy91bmFwLXRlc2lzL1JBRkFFTC1kYXRhL2FiX2hpc3QucG5nIikKCmMgPC0gYSArIAogIGdlb21fZGVuc2l0eShhbHBoYT0uNSxwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsgCiAgZmFjZXRfd3JhcCh+aWdnLCBzY2FsZT0gImZyZWUiLCBuY29sID0gNSkKI2dnc2F2ZSgiZGF0YS1yYXcvcmF3L3VuYXAtdGVzaXMvUkFGQUVMLWRhdGEvYWJfZGVucy5wbmciKQogICNmYWNldF93cmFwKHRyYW5zZm9ybX5tZWFzdXJlLHNjYWxlcyA9ICJmcmVlIikKClJtaXNjOjptdWx0aXBsb3QoYixjLGNvbHMgPSAxKQpgYGAKCmBgYHtyLGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTQsZXZhbD1GQUxTRX0KIyMjIyMgb2QKYSA8LSBtZG8gJT4lIAogIGdncGxvdChhZXMoeD1tZWFuLk9ELGZpbGw9cGhlbm8pKSArIHRoZW1lX2J3KCkgKwogIHNjYWxlX3hfbG9nMTAoKQoKYiA8LSBhICsKICBnZW9tX2hpc3RvZ3JhbShhbHBoYT0uNSxwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsgZmFjZXRfZ3JpZCh+aWdnKQojZ2dzYXZlKCJkYXRhLXJhdy9yYXcvdW5hcC10ZXNpcy9SQUZBRUwtZGF0YS9vZF9oaXN0LnBuZyIpCgpjIDwtIGEgKyAKICBnZW9tX2RlbnNpdHkoYWxwaGE9LjUscG9zaXRpb24gPSAiaWRlbnRpdHkiKSArIGZhY2V0X2dyaWQofmlnZykKI2dnc2F2ZSgiZGF0YS1yYXcvcmF3L3VuYXAtdGVzaXMvUkFGQUVMLWRhdGEvb2RfZGVucy5wbmciKQogICNmYWNldF93cmFwKHRyYW5zZm9ybX5tZWFzdXJlLHNjYWxlcyA9ICJmcmVlIikKClJtaXNjOjptdWx0aXBsb3QoYixjLGNvbHMgPSAxKQpgYGAKCiMgQ09WQVJJQVRFUwoKYGBge3J9CmNvdmEgPC0gcmVhZHhsOjpyZWFkX3hsc3goImRhdGEtcmF3L3Jhdy91bmFwLXRlc2lzL1JBRkFFTC1kYXRhL0Jhc2UgUmFmYWVsLnhsc3giLAogICAgICAgICAgICAgICAgICByYW5nZSA9ICJBMTpQNTkiLAogICAgICAgICAgICAgICAgICBzaGVldCA9IDEpICU+JSAKICBzbGljZSgtMSkgJT4lIAogIGRwbHlyOjpyZW5hbWUoRURBRD0iWF9fMSIsU0VYTz0iWF9fMiIpICU+JSAKICByZW5hbWVfYWxsKGZ1bnMoc3RyaW5ncjo6c3RyX3RvX2xvd2VyKC4pKSkgJT4lIAogIGRwbHlyOjpzZWxlY3QoY29kaWdvOmdhbWV0b2NpdG9zKSAlPiUgCiAgZHBseXI6OnNlbGVjdChjb2RpZ28sY29uZGljaW9uPSJjb25kaWNpw7NuIixlZGFkLHNleG8sY29tdW5pZGFkLGZpZWJyZSkKYGBgCgpgYGB7cn0KY292YiA8LSByZWFkeGw6OnJlYWRfeGxzeCgiZGF0YS1yYXcvcmF3L3VuYXAtdGVzaXMvUkFGQUVMLWRhdGEvREVOU0lEQURFUy54bHN4IiwKICAgICAgICAgICAgICAgICAgcmFuZ2UgPSAiQTE6RTU5IiwKICAgICAgICAgICAgICAgICAgc2hlZXQgPSAxKSAlPiUgCiAgc2xpY2UoLTEpICU+JSAKICByZW5hbWVfYWxsKGZ1bnMoc3RyaW5ncjo6c3RyX3RvX2xvd2VyKC4pKSkgJT4lIAogIGRwbHlyOjpzZWxlY3QoMTo0KSAlPiUgCiAgZHBseXI6OnJlbmFtZShwYXI9InBhcsOhc3Rpb3MvdWwgZGUgc2FuZ3JlIikgJT4lIAogIGRwbHlyOjpzZWxlY3QoLTQpICU+JSAKICBkcGx5cjo6cmVuYW1lKGNvbmRpY2lvbj0iY29uZGljacOzbiIpCmBgYAoKIyMjIyBtZXJnZSBpc3N1ZXMKCi0gX180IG11ZXN0cmFzX18gY29uIF9faW5jb21wYXRpYmlsaWRhZCBkZSBjb3ZhcmlhYmxlc19fIGVuIF9fYGVkYWRgX18geSBfX2BzZXhvYF9fLgogICAgKyBwcmlvcmlkYWQ6IGBwYXJhc2l0ZW1pYWAKICAgICsgcmV0aXJvIGRlIG9ic2VydmFjaW9uZXMgY29uIF9fYHBhcmA9MF9fCi0gwr92YXJpYWJsZSBgY29uZGljacOzbmA/CgotIFNPTFZFIFRISVMhISBBRkZFQ1RTIFtIRVJFXSgjdGlkeS11cCkKCmBgYHtyfQpjb3Z4IDwtIGZ1bGxfam9pbihjb3ZhLCBjb3ZiLCBieT0iY29kaWdvIikgCgpjb3Z4ICU+JSAKICBkcGx5cjo6Y291bnQoY29kaWdvKSAlPiUgYXJyYW5nZShkZXNjKG4pKSAlPiUgZmlsdGVyKG4hPTEpCgojY292eCAlPiUgZmlsdGVyKGNvZGlnbz09IjIyMzUiIHwgY29kaWdvPT0iMzA1MyIgfCBjb2RpZ289PSI5MTY1IiB8IGNvZGlnbz09Ijk4MDEiKSAlPiUgYXJyYW5nZShjb2RpZ28pICU+JSAKIyAgZHBseXI6OnNlbGVjdChjb2RpZ28sZWRhZCxzZXhvLHBhcikKY292YSAlPiUgZmlsdGVyKGNvZGlnbz09IjIyMzUiIHwgY29kaWdvPT0iMzA1MyIgfCBjb2RpZ289PSI5MTY1IiB8IGNvZGlnbz09Ijk4MDEiKSAlPiUgYXJyYW5nZShjb2RpZ28pICU+JSAKICBkcGx5cjo6c2VsZWN0KGNvZGlnbyxlZGFkLHNleG8pCmNvdmIgJT4lIGZpbHRlcihjb2RpZ289PSIyMjM1IiB8IGNvZGlnbz09IjMwNTMiIHwgY29kaWdvPT0iOTE2NSIgfCBjb2RpZ289PSI5ODAxIikgJT4lIGFycmFuZ2UoY29kaWdvKSAlPiUgCiAgZHBseXI6OnNlbGVjdChjb2RpZ28scGFyKQoKIyBwYXIgY292YXJpYXRlcyBmaW5hbGUKY292ZiA8LSBjb3ZiICU+JSBmaWx0ZXIoIShjb2RpZ289PSIyMjM1IiAmIHBhcj09MCB8IGNvZGlnbz09IjMwNTMiICYgcGFyPT0wIHwgY29kaWdvPT0iOTE2NSIgJiBwYXI9PTAgfCBjb2RpZ289PSI5ODAxIiAmIHBhcj09MCkpICU+JSAKICBkcGx5cjo6cmVuYW1lKElEPWNvZGlnbykKYGBgCgpgYGB7ciwgZXZhbD1GQUxTRX0KbWRvICU+JSBkcGx5cjo6Y291bnQoSUQpCmBgYAoKYGBge3J9Cm1jbyA8LSBmdWxsX2pvaW4obWRvLGNvdmYsYnk9IklEIikgJT4lICNkcGx5cjo6Y291bnQocGhlbm8sY29uZGljaW9uKQogIGRwbHlyOjpzZWxlY3QoLWNvbmRpY2lvbikgJT4lIAogIG11dGF0ZShBYi51bml0c19sb2c9bG9nMTAoQWIudW5pdHMpKQpgYGAKCiMjIyMgdGVzdCBjb3ZhcmlhdGVzCgpgYGB7cn0KbWN2IDwtIGNvdnggJT4lIAogICNmaWx0ZXIoY29kaWdvPT0iMjIzNSIgfCBjb2RpZ289PSIzMDUzIiB8IGNvZGlnbz09IjkxNjUiIHwgY29kaWdvPT0iOTgwMSIpICU+JSAKICBmaWx0ZXIoIShjb2RpZ289PSIyMjM1IiB8IAogICAgICAgICAgICAgY29kaWdvPT0iMzA1MyIgfCAKICAgICAgICAgICAgIGNvZGlnbz09IjkxNjUiIHwgCiAgICAgICAgICAgICBjb2RpZ289PSI5ODAxIikpICU+JSAKICAjZmlsdGVyKGNvZGlnbz09IjIyMzUiIHwgY29kaWdvPT0iMzA1MyIgfCBjb2RpZ289PSI5MTY1IiB8IGNvZGlnbz09Ijk4MDEiKSAlPiUgCiAgYXJyYW5nZShjb2RpZ28pICU+JSAKICBkcGx5cjo6c2VsZWN0KGNvZGlnbyxlZGFkLHNleG8scGFyKSAlPiUgCiAgZHBseXI6OnJlbmFtZShJRD1jb2RpZ28pICU+JSAKICBmdWxsX2pvaW4obWRvICU+JSAKICAgICAgICAgICAgICBncm91cF9ieShJRCkgJT4lIAogICAgICAgICAgICAgIHNsaWNlKDEpICU+JSAKICAgICAgICAgICAgICB1bmdyb3VwKCkKICAgICAgICAgICAgLGJ5PSJJRCIpICU+JSAKICBkcGx5cjo6c2VsZWN0KElELGVkYWQsc2V4byxwYXIscGhlbm8pICU+JSAKICAjbXV0YXRlKHNleG89Zm9yY2F0czo6ZmN0X3JlY29kZShzZXhvLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzZXgxIj0iMSIsICJzZXgwIj0iMCIpKSAlPiUgCiAgbXV0YXRlKHNleG89YXMuZmFjdG9yKHNleG8pLAogICAgICAgICBwaGVubz1hcy5mYWN0b3IocGhlbm8pLAogICAgICAgICBlZGFkPWFzLm51bWVyaWMoZWRhZCkpCmBgYAoKYGBge3IsZXJyb3I9VFJVRX0KbWN2X3UgPC0gSG1pc2M6OnVwRGF0YShtY3YgJT4lIGRwbHlyOjpzZWxlY3QoLUlEKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoZWRhZD0iQWdlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2V4bz0iU2V4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyPSJQYXJhc2l0ZSBkZW5zaXR5IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAgICAgdW5pdHMgPSBjKGVkYWQ9Iih5ZWFycykiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcj0iKHBhci91TCkiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGxpc3QocGhlbm89bGlzdCgiQXN5bXB0b21hdGljIj0iYXN5bXB0b21hdGljIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTeW1wdG9tYXRpYyI9InN5bXB0b21hdGljIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNleG89bGlzdCgiRmVtYWxlIj0iMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWFsZSI9IjEiKSAjPz8/CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICkKCkhtaXNjOjpodG1sKEhtaXNjOjpjb250ZW50cyhtY3ZfdSksIG1heGxldmVscz0xMCwgbGV2ZWxUeXBlPSd0YWJsZScpCmBgYAoKYGBge3IsZXJyb3I9VFJVRX0KczEgPC0gSG1pc2M6OnN1bW1hcnlNKHNleG8gKyBlZGFkICsgcGFyIH4gcGhlbm8sCiAgICAgICAgICAgICAgIGRhdGE9bWN2X3UsCiAgICAgICAgICAgICAgIG92ZXJhbGw9RkFMU0UsIHRlc3Q9VFJVRSkKCkhtaXNjOjpsYXRleChzMSwgY2FwdGlvbj0nU2FtcGxlIGNvdmFyaWF0ZXMnLAogICAgICBleGNsdWRlMT1UUlVFLCAjbnBjdD0nYm90aCcsIAogICAgICB0ZXN0PVRSVUUgLCBwcnRlc3Q9IlAiLGZpbGU9IiIsCiAgICAgIGRpZ2l0cz0zLCBwcm49RkFMU0UsCiAgICAgICNwcm1zZD1UUlVFLCBicm1zZD1UUlVFLCAjbXNkc2l6ZT1tdSRzbWFsbGVyMiwgI05PVC1FVkFMVUFURSBpZiBQREYKICAgICAgbWlkZGxlLmJvbGQ9VFJVRSwgbG9uZyA9IEZBTFNFLAogICAgICAjbGVnZW5kLmJvdHRvbSA9IFRSVUUsICNpbnNlcnQuYm90dG9tID0gVFJVRSwgCiAgICAgIHdoYXQ9IiUiLCBodG1sID0gVFJVRSwgCiAgICAgIHdpZHRoPSIxMDAlIgogICAgICApICNjaGFuZ2UgaGVyZSBmb3IgTGFUZVggUERGCmBgYAoKYGBge3J9CnJlYWRyOjp3cml0ZV9yZHMobWN2X3UsImRhdGEvdW5hcC1yYWZhLWNvdmFyLnJkcyIpCmBgYAoKCiMgU0VST0xPR0lDQUwgQ0xBU1NJRklDQVRJT04KCiMjIFRvIERvCgotIEltcGxlbWVudCB0aGUgbWVhbiAvIFJPQyAvIG1peHR1cmUgbW9kZWxzIG1ldGhvZAoKIyMgbWl4dG9vbHMKCiMjIyBjaGVjayBkaXN0cmlidXRpb25zCgpgYGB7cixmaWcud2lkdGg9NyxmaWcuaGVpZ2h0PTIuNX0KYSA8LSBtY28gJT4lICNmaWx0ZXIoaWdnPT0iaWdnMyIpICU+JSAKICBnZ3Bsb3QoYWVzKHg9QWIudW5pdHMKICAgICAgICAgICAgICMsZmlsbD1waGVubwogICAgICAgICAgICAgIyxmaWxsPWlnZwogICAgICAgICAgICAgKSkgKyB0aGVtZV9idygpICsKICAjc2NhbGVfeF9sb2cxMCgpICsKICBnZW9tX2RlbnNpdHkoYWxwaGE9LjUscG9zaXRpb24gPSAiaWRlbnRpdHkiKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHg9QWIudW5pdHMsLi5kZW5zaXR5Li4pLAogICAgICAgICAgICAgICAgIGFscGhhPS41LHBvc2l0aW9uID0gImlkZW50aXR5IikgKwogICN0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArCiAgbGFicyh0aXRsZT0iQVUgbGluZWFyIGRpc3RyaWJ1dGlvbiIpCgpiIDwtIG1jbyAlPiUgI2ZpbHRlcihpZ2c9PSJpZ2czIikgJT4lIAogIGdncGxvdChhZXMoc2FtcGxlPUFiLnVuaXRzCiAgICAgICAgICAgICAjLGZpbGw9cGhlbm8KICAgICAgICAgICAgICMsZmlsbD1pZ2cKICAgICAgICAgICAgICkpICsKICBnZW9tX3FxKGFscGhhPS4yKSArCiAgZ2VvbV9xcV9saW5lKGxpbmUucCA9IGMoMC4yNSwgMC43NSkpICsKICBsYWJzKHRpdGxlPSJHYXVzc2lhbiBxdWFudGlsZS1xdWFudGlsZSBwbG90IikgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLDIwMDApKQoKUm1pc2M6Om11bHRpcGxvdChhLGIsY29scyA9IDIpCmBgYAoKCmBgYHtyLGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTIuMn0KbWNvICU+JSAKICBnZ3Bsb3QoYWVzKHg9QWIudW5pdHMKICAgICAgICAgICAgICMsZmlsbD1waGVubwogICAgICAgICAgICAgKSkgKyB0aGVtZV9idygpICsKICAjc2NhbGVfeF9sb2cxMCgpICsKICBnZW9tX2RlbnNpdHkoYWxwaGE9LjUscG9zaXRpb24gPSAiaWRlbnRpdHkiLGFkanVzdD0gMS8yCiAgICAgICAgICAgICAgICkgKyAKICBnZW9tX2hpc3RvZ3JhbShhZXMoeD1BYi51bml0cywuLmRlbnNpdHkuLiksCiAgICAgICAgICAgICAgICAgYWxwaGE9LjUscG9zaXRpb24gPSAiaWRlbnRpdHkiKSArIAogIGZhY2V0X3dyYXAofmlnZywgc2NhbGVzID0gImZyZWUiLG5jb2wgPSA1KSArCiAgbGFicyh0aXRsZT0iQVUgbGluZWFyIGRpc3RyaWJ1dGlvbiBwZXIgSWdHIHN1YnR5cGUiKQpgYGAKCiMjIyBhcHBseSBtaXh0b29scwoKYGBge3J9CiMgc291cmNlOiBodHRwOi8vdGlueWhlZXJvLmdpdGh1Yi5pby8yMDE1LzEwLzEzL21peHR1cmUtbW9kZWwuaHRtbApmIDwtIG1jbyAlPiUgbXV0YXRlKGlnZz1hcy5mYWN0b3IoaWdnKSkgJT4lIAogIG11dGF0ZShpZ2c9Zm9yY2F0czo6ZmN0X3JlbGV2ZWwoaWdnLCJpZ2ciLCJpZ2cxIiwiaWdnMiIsImlnZzMiKSkgJT4lIC4kaWdnCgojbGlicmFyeSgibWl4dG9vbHMiKQoKIycgUGxvdCBhIE1peHR1cmUgQ29tcG9uZW50CiMnIAojJyBAcGFyYW0geCBJbnB1dCBkYXRhCiMnIEBwYXJhbSBtdSBNZWFuIG9mIGNvbXBvbmVudAojJyBAcGFyYW0gc2lnbWEgU3RhbmRhcmQgZGV2aWF0aW9uIG9mIGNvbXBvbmVudAojJyBAcGFyYW0gbGFtIE1peHR1cmUgd2VpZ2h0IG9mIGNvbXBvbmVudApwbG90X21peF9jb21wcyA8LSBmdW5jdGlvbih4LCBtdSwgc2lnbWEsIGxhbSkgewogIGxhbSAqIGRub3JtKHgsIG11LCBzaWdtYSkKfQoKc2V0LnNlZWQoMSkKI2xlbmd0aChsZXZlbHMoZikpCiN3YWl0IDwtIG1jbyAlPiUgZmlsdGVyKGlnZz09ImlnZzIiKSAlPiUgCiMgIC4kQWIudW5pdHMgJT4lIGxvZygpCgpsbG1peCA8LSBkYXRhX2ZyYW1lKGlnZz1hcy5jaGFyYWN0ZXIoKSwKICAgICAgICAgICAgICAgICAgICBrcHI9YXMubnVtZXJpYygpLAogICAgICAgICAgICAgICAgICAgIGxpaz1hcy5udW1lcmljKCkpCmZvciAoaiBpbiAyOjMpIHsKICAgIAogICAgbWl4bWRsX3AgPC0gbm9ybWFsbWl4RU0obWNvICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2ZpbHRlcihpZ2c9PWxldmVscyhmKVtpXSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuJEFiLnVuaXRzICMlPiUgbG9nMTAoKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGsgPSBqKQogICAgbGxtaXggPC0gbGxtaXggJT4lIAogICAgICB1bmlvbihkYXRhX2ZyYW1lKGlnZz0iYWxsIiwjbGV2ZWxzKGYpW2ldLAogICAgICAgICAgICAgICAgICAgICAgIGtwcj1qLAogICAgICAgICAgICAgICAgICAgICAgIGxpaz1taXhtZGxfcCRsb2dsaWspKQogICAgCiAgfQpsbG1peCAlPiUgYXJyYW5nZShpZ2csZGVzYyhsaWspKSAlPiUgbXV0YXRlKGFpYz0yKmtwci0yKmxpaykKCiMKbGxtaXggPC0gZGF0YV9mcmFtZShpZ2c9YXMuY2hhcmFjdGVyKCksCiAgICAgICAgICAgICAgICAgICAga3ByPWFzLm51bWVyaWMoKSwKICAgICAgICAgICAgICAgICAgICBsaWs9YXMubnVtZXJpYygpKQpmb3IgKGkgaW4gMTpsZW5ndGgobGV2ZWxzKGYpKSkgewogIAogIGZvciAoaiBpbiAyOjMpIHsKICAgIAogICAgbWl4bWRsX3AgPC0gbm9ybWFsbWl4RU0obWNvICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKGlnZz09bGV2ZWxzKGYpW2ldKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4kQWIudW5pdHMgIyU+JSBsb2cxMCgpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgayA9IGopCiAgICBsbG1peCA8LSBsbG1peCAlPiUgCiAgICAgIHVuaW9uKGRhdGFfZnJhbWUoaWdnPWxldmVscyhmKVtpXSwKICAgICAgICAgICAgICAgICAgICAgICBrcHI9aiwKICAgICAgICAgICAgICAgICAgICAgICBsaWs9bWl4bWRsX3AkbG9nbGlrKSkKICAgIAogIH0KICAKfQpsbG1peCAlPiUgYXJyYW5nZShpZ2csZGVzYyhsaWspKSAlPiUgbXV0YXRlKGFpYz0yKmtwci0yKmxpaykgIyU+JSAKICAjZ3JvdXBfYnkoaWdnKSAlPiUgZmlsdGVyKGxpaz09bWF4KGxpaykpCgojbWl4bWRsIDwtIG5vcm1hbG1peEVNKHdhaXQsIGsgPSAzKQojbWl4bWRsJGxvZ2xpawpgYGAKCmBgYHtyLGZpZy5oZWlnaHQ9MyxmaWcud2lkdGg9MTJ9CiMjIyBGT1IgQUxMIEFCLlVOSVRTIChOTyBJR0cgU1VCVFlQRVMpCnNldC5zZWVkKDEpCgojZm9yIChpIGluIDE6bGVuZ3RoKGxldmVscyhmKSkpIHsKICAKd2FpdCA8LSBtY28gJT4lICNmaWx0ZXIoaWdnPT1sZXZlbHMoZilbaV0pICU+JSAKICAuJEFiLnVuaXRzICMlPiUgbG9nMTAoKQptaXhtZGwgPC0gbm9ybWFsbWl4RU0od2FpdCwgayA9IDMpCiMjIwpyIDwtIGRhdGEuZnJhbWUoeCA9IG1peG1kbCR4KSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHgsIC4uZGVuc2l0eS4uKSwgCiAgICAgICAgICAgICAgICAgI2JpbndpZHRoID0gMSwgCiAgICAgICAgICAgICAgICAgI2NvbG91ciA9ICJibGFjayIsIAogICAgICAgICAgICAgICAgICNmaWxsID0gImdyYXkiLAogICAgICAgICAgICAgICAgIGFscGhhPS41LHBvc2l0aW9uID0gImlkZW50aXR5IgogICAgICAgICAgICAgICAgICkgKwogIHN0YXRfZnVuY3Rpb24oZ2VvbSA9ICJsaW5lIiwgCiAgICAgICAgICAgICAgICBmdW4gPSBwbG90X21peF9jb21wcywKICAgICAgICAgICAgICAgIGFyZ3MgPSBsaXN0KG1peG1kbCRtdVsxXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaXhtZGwkc2lnbWFbMV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFtID0gbWl4bWRsJGxhbWJkYVsxXSksCiAgICAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JlZW4iLCBsd2QgPSAxLjUpICsKICBzdGF0X2Z1bmN0aW9uKGdlb20gPSAibGluZSIsIAogICAgICAgICAgICAgICAgZnVuID0gcGxvdF9taXhfY29tcHMsCiAgICAgICAgICAgICAgICBhcmdzID0gbGlzdChtaXhtZGwkbXVbMl0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbWl4bWRsJHNpZ21hWzJdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhbSA9IG1peG1kbCRsYW1iZGFbMl0pLAogICAgICAgICAgICAgICAgY29sb3VyID0gImJsdWUiLCBsd2QgPSAxLjUpICsKICBzdGF0X2Z1bmN0aW9uKGdlb20gPSAibGluZSIsIAogICAgICAgICAgICAgICAgZnVuID0gcGxvdF9taXhfY29tcHMsCiAgICAgICAgICAgICAgICBhcmdzID0gbGlzdChtaXhtZGwkbXVbM10sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbWl4bWRsJHNpZ21hWzNdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhbSA9IG1peG1kbCRsYW1iZGFbM10pLAogICAgICAgICAgICAgICAgY29sb3VyID0gInJlZCIsIGx3ZCA9IDEuNSkgKwogIHlsYWIoIkRlbnNpdHkiKSArCiAgeGxhYigiQWIudW5pdHMiKSArCiAgbGFicyh0aXRsZT0gcGFzdGUwKCJBYi51bml0czogIiwKICAgICAgICAgICAgICAgICAgICAgI2lmZWxzZShsZXZlbHMoZilbaV09PSJpZ2ciLCJJZ0cgIiwKICAgICAgICAgICAgICAgICAgICAgICMgICAgICBpZmVsc2UobGV2ZWxzKGYpW2ldPT0iaWdnMSIsIklnRzEgIiwKICAgICAgICAgICAgICAgICAgICAgICAgIyAgICAgICAgICAgaWZlbHNlKGxldmVscyhmKVtpXT09ImlnZzIiLCJJZ0cyICIsCiAgICAgICAgICAgICAgICAgICAgICAgICAjICAgICAgICAgICAgICAgICBpZmVsc2UobGV2ZWxzKGYpW2ldPT0iaWdnMyIsIklnRzMgIiwiSWdHNCAiKQogICAgICAgICAgICAgICAgICAgICAgICAgICMgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICMgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgIyAgKSwKICAgICAgICAgICAgICAgICAgICAgIjMtY29tcG9uZW50IGRpc3RyaWJ1dGlvbiIKICAgICAgICAgICAgICAgICAgICAgIywiOiBMb2dMaWs9IiwKICAgICAgICAgICAgICAgICAgICAgI21peG1kbCRsb2dsaWsgJT4lIGZvcm1hdChkaWdpdHM9MykKICAgICAgICAgICAgICAgICAgICAgKSkgCiAgIysgc2NhbGVfeF9sb2cxMCgpCgojIyMjCnUgPC0gMC45MCAjIDkwJSBjbGFzc2lmaWNhdGlvbiBwcm9iYWJpbGl0eQoKcG9zdC5kZiA8LSBhcy5kYXRhLmZyYW1lKGNiaW5kKHggPSBtaXhtZGwkeCwgbWl4bWRsJHBvc3RlcmlvcikpICU+JSAKICBtdXRhdGUoY29tcC4xMj1jb21wLjErY29tcC4yKSAlPiUgIyBzdW0gcHJvYmFiaWxpdGllcyBvZiBzKyBhbmQgcysrCiAgbXV0YXRlKGxhYmVsID0gaWZlbHNlKGNvbXAuMyA+IHUsICJzLSIsIAogICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoY29tcC4xMiA+IHUsICJzKyIsICJzMCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNpZmVsc2UoY29tcC4xID4gdSwicysrIiwiczAiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkpICU+JSAKICBtdXRhdGUobGFiZWw9Zm9yY2F0czo6ZmN0X3JlbGV2ZWwobGFiZWwsInMtIiwiczAiLCJzKyIjLCJzKysiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpCgpzIDwtIHBvc3QuZGYgJT4lIAogIGdncGxvdChhZXMoeCA9IGZhY3RvcihsYWJlbCkpKSArCiAgZ2VvbV9iYXIoKSArCiAgeGxhYigiQ29tcG9uZW50IikgKwogIHlsYWIoIk51bWJlciBvZiBEYXRhIFBvaW50cyIpICsKICBsYWJzKHRpdGxlPSJDbGFzc2lmaWNhdGlvbiIpCgojIyMKdCA8LSBwb3N0LmRmICU+JSAKICBnZ3Bsb3QoKSArCiAgI2dlb21fbGluZShhZXMoeCxjb21wLjEpLCBjb2xvdXI9ImdyZWVuIiwgbHdkID0gMS41KSArCiAgI2dlb21fbGluZShhZXMoeCxjb21wLjIpLCBjb2xvdXI9ImJsdWUiLCBsd2QgPSAxLjUpICsKICBnZW9tX2xpbmUoYWVzKHgsY29tcC4xMiksIGNvbG91cj0iYmx1ZSIsIGx3ZCA9IDEuNSkgKwogIGdlb21fbGluZShhZXMoeCxjb21wLjMpLCBjb2xvdXI9InJlZCIsIGx3ZCA9IDEuNSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IHUsIGNvbCA9ICJibGFjayIpICsKICAjZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gY3V0b2Zmc1syXSwgY29sID0gImJsYWNrIiwgbHR5PTMpICsKICAjZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gY3V0b2Zmc1sxXSwgY29sID0gImJsYWNrIiwgbHR5PTMpICsKICB4bGFiKCJBYi51bml0cyIpICsKICB5bGFiKCJjbGFzc2lmaWNhdGlvbiBwcm9iYWJpbGl0eSIpICsKICBsYWJzKHRpdGxlPSJDdXRvZmYiKQoKUm1pc2M6Om11bHRpcGxvdChyLHQscyxjb2xzID0gMykKICAKI30KCiNzdW0obWNvJEFiLnVuaXRzX2xvZyA9PSBtaXhtZGwkeCkKI2xlbmd0aChtaXhtZGwkeCkKI3N1bSghcG9zdC5kZiR4PT1tY28kQWIudW5pdHNfbG9nKQoKbXNyIDwtIGlubmVyX2pvaW4obWNvICU+JSByb3duYW1lc190b19jb2x1bW4oKSwKICAgICAgICAgICBwb3N0LmRmICU+JQogICAgICAgICAgICAgI2RwbHlyOjpyZW5hbWUoQWIudW5pdHNfbG9nPXgpICU+JSAKICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoI0FiLnVuaXRzX2xvZywKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwpICU+JSAKICAgICAgICAgICAgIHJvd25hbWVzX3RvX2NvbHVtbigpLAogICAgICAgICAgIGJ5PSJyb3duYW1lIikgIyU+JSAKICAjbXV0YXRlKHRlc3Q9IEFiLnVuaXRzX2xvZy54PT1BYi51bml0c19sb2cueSkgJT4lIGRwbHlyOjpjb3VudCh0ZXN0KQoKbXNyIDwtIG1zcltGQUxTRSxdICMlPiUgZ2xpbXBzZSgpCmBgYAoKIyMjIDItY29tcG9uZW50CgpgYGB7cixmaWcuaGVpZ2h0PTMsZmlnLndpZHRoPTEyLGV2YWw9RkFMU0V9CgpzZXQuc2VlZCgxKQoKZm9yIChpIGluIDE6bGVuZ3RoKGxldmVscyhmKSkpIHsKICAKd2FpdCA8LSBtY28gJT4lIGZpbHRlcihpZ2c9PWxldmVscyhmKVtpXSkgJT4lIAogIC4kQWIudW5pdHMgIyU+JSBsb2cxMCgpCm1peG1kbCA8LSBub3JtYWxtaXhFTSh3YWl0LCBrID0gMykKIyMjCnIgPC0gZGF0YS5mcmFtZSh4ID0gbWl4bWRsJHgpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeCwgLi5kZW5zaXR5Li4pLCAKICAgICAgICAgICAgICAgICAjYmlud2lkdGggPSAxLCAKICAgICAgICAgICAgICAgICAjY29sb3VyID0gImJsYWNrIiwgCiAgICAgICAgICAgICAgICAgI2ZpbGwgPSAiZ3JheSIsCiAgICAgICAgICAgICAgICAgYWxwaGE9LjUscG9zaXRpb24gPSAiaWRlbnRpdHkiCiAgICAgICAgICAgICAgICAgKSArCiAgc3RhdF9mdW5jdGlvbihnZW9tID0gImxpbmUiLCAKICAgICAgICAgICAgICAgIGZ1biA9IHBsb3RfbWl4X2NvbXBzLAogICAgICAgICAgICAgICAgYXJncyA9IGxpc3QobWl4bWRsJG11WzFdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1peG1kbCRzaWdtYVsxXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYW0gPSBtaXhtZGwkbGFtYmRhWzFdKSwKICAgICAgICAgICAgICAgIGNvbG91ciA9ICJyZWQiLCBsd2QgPSAxLjUpICsKICBzdGF0X2Z1bmN0aW9uKGdlb20gPSAibGluZSIsIAogICAgICAgICAgICAgICAgZnVuID0gcGxvdF9taXhfY29tcHMsCiAgICAgICAgICAgICAgICBhcmdzID0gbGlzdChtaXhtZGwkbXVbMl0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbWl4bWRsJHNpZ21hWzJdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhbSA9IG1peG1kbCRsYW1iZGFbMl0pLAogICAgICAgICAgICAgICAgY29sb3VyID0gImJsdWUiLCBsd2QgPSAxLjUpICsKICAjc3RhdF9mdW5jdGlvbihnZW9tID0gImxpbmUiLCAKICAjICAgICAgICAgICAgICBmdW4gPSBwbG90X21peF9jb21wcywKICAjICAgICAgICAgICAgICBhcmdzID0gbGlzdChtaXhtZGwkbXVbM10sIAogICMgICAgICAgICAgICAgICAgICAgICAgICAgIG1peG1kbCRzaWdtYVszXSwgCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgbGFtID0gbWl4bWRsJGxhbWJkYVszXSksCiAgIyAgICAgICAgICAgICAgY29sb3VyID0gImdyZWVuIiwgbHdkID0gMS41KSArCiAgeWxhYigiRGVuc2l0eSIpICsKICB4bGFiKCJBYi51bml0cyIpICsKICBsYWJzKHRpdGxlPSBwYXN0ZTAoaWZlbHNlKGxldmVscyhmKVtpXT09ImlnZyIsIklnRzogIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShsZXZlbHMoZilbaV09PSJpZ2cxIiwiSWdHMTogIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UobGV2ZWxzKGYpW2ldPT0iaWdnMiIsIklnRzI6ICIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShsZXZlbHMoZilbaV09PSJpZ2czIiwiSWdHMyAiLCJJZ0c0OiAiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgICAgICAgICAgIjMtY29tcG9uZW50IGRpc3RyaWJ1dGlvbiIKICAgICAgICAgICAgICAgICAgICAgIywiOiBMb2dMaWs9IiwKICAgICAgICAgICAgICAgICAgICAgI21peG1kbCRsb2dsaWsgJT4lIGZvcm1hdChkaWdpdHM9MykKICAgICAgICAgICAgICAgICAgICAgKSkgCiAgIysgc2NhbGVfeF9sb2cxMCgpCgojIyMjCnUgPC0gMC45MCAjIDkwJSBjbGFzc2lmaWNhdGlvbiBwcm9iYWJpbGl0eQoKcG9zdC5kZiA8LSBhcy5kYXRhLmZyYW1lKGNiaW5kKHggPSBtaXhtZGwkeCwgbWl4bWRsJHBvc3RlcmlvcikpICU+JSAKICBtdXRhdGUoY29tcC5zcD1pZmVsc2UobWVhbihjb21wLjIpPjEwMCwKICAgICAgICAgICAgICAgICAgICAgICAgY29tcC4yK2NvbXAuMywKICAgICAgICAgICAgICAgICAgICAgICAgY29tcC4xK2NvbXAuMikpICU+JSAjIHN1bSBwcm9iYWJpbGl0aWVzIG9mIHMrIGFuZCBzKysKICBtdXRhdGUobGFiZWwgPSBpZmVsc2UoY29tcC4xID4gdSwgInMtIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICNpZmVsc2UoY29tcC5zcCA+IHUsICJzKyIsICJzMCIKICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGNvbXAuMiA+IHUsICJzKyIsICJzMCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNpZmVsc2UoY29tcC4xID4gdSwicysrIiwiczAiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkpICU+JSAKICBtdXRhdGUobGFiZWw9Zm9yY2F0czo6ZmN0X3JlbGV2ZWwobGFiZWwsInMtIiwiczAiLCJzKyIjLCJzKysiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpIAoKcyA8LSBwb3N0LmRmICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBmYWN0b3IobGFiZWwpKSkgKwogIGdlb21fYmFyKCkgKwogIHhsYWIoIkNvbXBvbmVudCIpICsKICB5bGFiKCJOdW1iZXIgb2YgRGF0YSBQb2ludHMiKSArCiAgbGFicyh0aXRsZT0iQ2xhc3NpZmljYXRpb24iKQoKIyMjCnQgPC0gcG9zdC5kZiAlPiUgCiAgZ2dwbG90KCkgKwogICNnZW9tX2xpbmUoYWVzKHgsY29tcC4xKSwgY29sb3VyPSJncmVlbiIsIGx3ZCA9IDEuNSkgKwogIGdlb21fbGluZShhZXMoeCxjb21wLjIpLCBjb2xvdXI9ImJsdWUiLCBsd2QgPSAxLjUpICsKICAjZ2VvbV9saW5lKGFlcyh4LGNvbXAuc3ApLCBjb2xvdXI9ImJsdWUiLCBsd2QgPSAxLjUpICsKICBnZW9tX2xpbmUoYWVzKHgsY29tcC4xKSwgY29sb3VyPSJyZWQiLCBsd2QgPSAxLjUpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSB1LCBjb2wgPSAiYmxhY2siKSArCiAgI2dlb21fdmxpbmUoeGludGVyY2VwdCA9IDYzLjYsIGNvbCA9ICJibGFjayIsIGx0eT0zKSArCiAgI2dlb21fdmxpbmUoeGludGVyY2VwdCA9IDY5LjcsIGNvbCA9ICJibGFjayIsIGx0eT0zKSArCiAgeGxhYigiQWIudW5pdHMiKSArCiAgeWxhYigiY2xhc3NpZmljYXRpb24gcHJvYmFiaWxpdHkiKSArCiAgbGFicyh0aXRsZT0iQ3V0b2ZmIikKCgojIyMKbXNyX3AgPC0gaW5uZXJfam9pbihtY28gJT4lCiAgICAgICAgICAgICAgICAgICAgZmlsdGVyKGlnZz09bGV2ZWxzKGYpW2ldKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgcm93bmFtZXNfdG9fY29sdW1uKCksCiAgICAgICAgICAgcG9zdC5kZiAlPiUKICAgICAgICAgICAgICNkcGx5cjo6cmVuYW1lKEFiLnVuaXRzX2xvZz14KSAlPiUgCiAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KCNBYi51bml0c19sb2csCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsKSAlPiUgCiAgICAgICAgICAgICByb3duYW1lc190b19jb2x1bW4oKSwKICAgICAgICAgICBieT0icm93bmFtZSIpICMlPiUgCiAgI211dGF0ZSh0ZXN0PSBBYi51bml0c19sb2cueD09QWIudW5pdHNfbG9nLnkpICU+JSBkcGx5cjo6Y291bnQodGVzdCkKCgptc3IgPC0gdW5pb24obXNyLCBtc3JfcCkKCgpSbWlzYzo6bXVsdGlwbG90KHIsdCxzLGNvbHMgPSAzKQogIAp9CmBgYAoKIyMjIHRocmVlIGNvbXBvbmVudCBkaXN0cmlidXRpb24KCi0gUG9zc2libGUgbWlzdGFrZSBmb3IgX19JZ0cyX18gYW5kIF9fSWdHNF9fOiAKICAgICsgRGVmaW5pdGlvbiBvZiBfUy1fIHVzaW5nIG9ubHkgdGhlIDFzdCBjb21wb25lbnQgYW5kIF9TK18gdXNpbmcgdGhlIDJuZCBhbmQgM3JkIG9uZSwgYXMgd2FzIHN0YW5kYXJkaXplZCBmb3IgYWxsIHRoZSBgaWdnIHN1YnR5cGVzYC4KICAgICsgX19DT1JSRUNUSU9OX186IElmIDJuZCBjb21wb25lbnQgaGF2ZSBhIG1lYW4gQVUgX19sb3dlciB0aGFuIGFuIEFSQklUUkFSWSBUSFJFU0hPTERfXywgZGVmaW5lIF9TK18gYXMgdGhlIHN1bSBvZiBvbmx5IHRoZSAzcmQgY29tcG9uZW50IHByb2JhYmlsaXRpZXMuCiAgICAgICAgLSBSRVNVTFQ6IGEgdGhyZXNob2xkIG9mIF9fMTAwX18gZ2l2ZSByZXN1bHRzIGFzIGV4cGVjdGVkIGZvciBgaWdnMmAgYW5kIGBpZ2c0YCBzZXJvcG9zaXRpdml0eS4KICAgICAgICAgICAgKyBJTiBSRUZFUkVOQ0U6IF9fUm91aGFuaSAyMDE1IChmaWd1cmUgMilfXy4KICAgICAgICAgICAgKyBBQ0hJRVZFRCBDUklURVJJQTogbG93ZXIgcHJvcG9ydGlvbiBvZiBpbmRldGVybWluZWQgc2Vyb2xvZ3kgYHMwYAogICAgICAgIC0gQUxURVJOQVRJVkU6IGEgdGhyZXNob2xkIG9mIF9fNDBfXyBtYXkgYmUgY29udmluaWVudCBmb3IgYGlnZzRgIGluIG9yZGVyIHRvIGV4cGxhaW4gaXRzOgogICAgICAgICAgICArIHNpZ25pZmljYW50bHkgaGlnaGVyIG1lYW4gQVUgaW4gc3ltcHRvbWF0aWNzLCBhbmQKICAgICAgICAgICAgKyBzdHJvbmcgYXNzb2NpYXRpb24gdG8gc3ltcHRvbWF0aWMgc3VzY2VwdGliaWxpdHkuCiAgICAgICAgICAgICsgQWNjb3JkaW5nIHRvIHRoZSBjb21wb25lbnQgQ0xBU1NJRklDQVRJT04gQ1JJVEVSSUEgYmFzZWQgb24gdGhlIHByb3BvcnRpb24gb2YgYHMwYCwgd2hpY2ggaXMgaGlnaGVyIHRoYW4gdGhlIHByZXZpb3VzIHRocmVzaG9sZCwgdGhpcyBpcyBub3QgdGhlIGJlc3QgY2xhc3NpZmljYXRpb24uCiAgICAgICAgICAgICsgSG93ZXZlciwgaWYgYSBib29zdCBvciBvdGhlciBwaGVub21lbmEgKGluY2x1ZGluZyBhIGRpZmZlcmVudCBnZW5vdHlwZSB3aXRoaW4gdGhlIHN0dWR5IHBvcHVsYXRpb24pIHRoYXQgaW5jcmVhc2UgdGhlIHByb3BvcnRpb24gb2YgSWdHNCBkdXJpbmcgYSBzeW1wdG9tYXRpYyBlcGlzb2RlIGlzIGFzc3VtZWQsIHRoaXMgbWF5IGJlIHRoZSByaWdodCBvbmUuCiAgICAgICAgICAgICsgSW50ZXJlc3RpbmdseSwgdGhpcyAybmQgY29tcG9uZW50IGlzIGZ1bGwgb2Ygc3ltcHRvbWF0aWMgc2FtcGxlcy4KICAgICsgTk9URTogRXZlbiB0aG91Z2ggdGhlIG1lYW4gb2YgdGhlIDJuZCBjb21wb25lbnQgaXMgaGlnaGVyIHRoYW4gMTAwLCBmb3IgYGlnZ2AgdGhlIHRocmVzaG9sZCBvZiBzZXJvcG9zaXRpdml0eSBpcyBsb3dlciB0aGFuIDQwIEFVLCB1bmRlciB0aGUgcmlnaHQgY3JpdGVyaWEuCgoKYGBge3IsZmlnLmhlaWdodD0zLGZpZy53aWR0aD0xMn0Kc2V0LnNlZWQoMSkKCiMgaT0gMwpmb3IgKGkgaW4gMTpsZW5ndGgobGV2ZWxzKGYpKSkgewogIAp3YWl0IDwtIG1jbyAlPiUgZmlsdGVyKGlnZz09bGV2ZWxzKGYpW2ldKSAlPiUgCiAgLiRBYi51bml0cyAjJT4lIGxvZzEwKCkKbWl4bWRsIDwtIG5vcm1hbG1peEVNKHdhaXQsIGsgPSAzKQojIyMKciA8LSBkYXRhLmZyYW1lKHggPSBtaXhtZGwkeCkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4LCAuLmRlbnNpdHkuLiksIAogICAgICAgICAgICAgICAgICNiaW53aWR0aCA9IDEsIAogICAgICAgICAgICAgICAgICNjb2xvdXIgPSAiYmxhY2siLCAKICAgICAgICAgICAgICAgICAjZmlsbCA9ICJncmF5IiwKICAgICAgICAgICAgICAgICBhbHBoYT0uNSxwb3NpdGlvbiA9ICJpZGVudGl0eSIKICAgICAgICAgICAgICAgICApICsKICBzdGF0X2Z1bmN0aW9uKGdlb20gPSAibGluZSIsIAogICAgICAgICAgICAgICAgZnVuID0gcGxvdF9taXhfY29tcHMsCiAgICAgICAgICAgICAgICBhcmdzID0gbGlzdChtaXhtZGwkbXVbMV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbWl4bWRsJHNpZ21hWzFdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhbSA9IG1peG1kbCRsYW1iZGFbMV0pLAogICAgICAgICAgICAgICAgY29sb3VyID0gInJlZCIsIGx3ZCA9IDEuNSkgKwogIHN0YXRfZnVuY3Rpb24oZ2VvbSA9ICJsaW5lIiwgCiAgICAgICAgICAgICAgICBmdW4gPSBwbG90X21peF9jb21wcywKICAgICAgICAgICAgICAgIGFyZ3MgPSBsaXN0KG1peG1kbCRtdVsyXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaXhtZGwkc2lnbWFbMl0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFtID0gbWl4bWRsJGxhbWJkYVsyXSksCiAgICAgICAgICAgICAgICBjb2xvdXIgPSAiYmx1ZSIsIGx3ZCA9IDEuNSkgKwogIHN0YXRfZnVuY3Rpb24oZ2VvbSA9ICJsaW5lIiwgCiAgICAgICAgICAgICAgICBmdW4gPSBwbG90X21peF9jb21wcywKICAgICAgICAgICAgICAgIGFyZ3MgPSBsaXN0KG1peG1kbCRtdVszXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaXhtZGwkc2lnbWFbM10sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFtID0gbWl4bWRsJGxhbWJkYVszXSksCiAgICAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JlZW4iLCBsd2QgPSAxLjUpICsKICB5bGFiKCJEZW5zaXR5IikgKwogIHhsYWIoIkFiLnVuaXRzIikgKwogIGxhYnModGl0bGU9IHBhc3RlMChpZmVsc2UobGV2ZWxzKGYpW2ldPT0iaWdnIiwiSWdHOiAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGxldmVscyhmKVtpXT09ImlnZzEiLCJJZ0cxOiAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShsZXZlbHMoZilbaV09PSJpZ2cyIiwiSWdHMjogIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGxldmVscyhmKVtpXT09ImlnZzMiLCJJZ0czICIsIklnRzQ6ICIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICAgICAgICAiMy1jb21wb25lbnQgZGlzdHJpYnV0aW9uIgogICAgICAgICAgICAgICAgICAgICAjLCI6IExvZ0xpaz0iLAogICAgICAgICAgICAgICAgICAgICAjbWl4bWRsJGxvZ2xpayAlPiUgZm9ybWF0KGRpZ2l0cz0zKQogICAgICAgICAgICAgICAgICAgICApKSAKICAjKyBzY2FsZV94X2xvZzEwKCkKCiMjIyMKdSA8LSAwLjkwICMgOTAlIGNsYXNzaWZpY2F0aW9uIHByb2JhYmlsaXR5Cgpwb3N0LmRmIDwtIGFzLmRhdGEuZnJhbWUoY2JpbmQoeCA9IG1peG1kbCR4LCBtaXhtZGwkcG9zdGVyaW9yKSkgJT4lIAogICNtdXRhdGUoY29tcC4xMj1jb21wLjErY29tcC4yLAogICMgICAgICAgY29tcC4yMz1jb21wLjIrY29tcC4zKSAlPiUgCiAgbXV0YXRlKGNvbXAuc3A9aWZfZWxzZShyZXAobWl4bWRsJG11WzJdPjQwLGxlbmd0aChtaXhtZGwkeCkpLCAjIFVNQlJBTCBBUkJJVFJBUklPISEKICAgICAgICAgICAgICAgICAgICAgICAgY29tcC4yK2NvbXAuMywgIyBzZXJvKyBlcXVhbHMgdG8gdGhlIHN1bSBvZiBjb21wIDIrMwogICAgICAgICAgICAgICAgICAgICAgICBjb21wLjMpKSAlPiUgIyBzZXJvKyBlcXVhbHMgdG8gdGhlIHN1bSBvZiBjb21wIDMKICBtdXRhdGUoY29tcC5zbj1pZl9lbHNlKHJlcChtaXhtZGwkbXVbMl0+NDAsbGVuZ3RoKG1peG1kbCR4KSksCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbXAuMSwgIyBzZXJvLSBlcXVhbHMgdG8gdGhlIHN1bSBvZiBjb21wIDEKICAgICAgICAgICAgICAgICAgICAgICAgY29tcC4xK2NvbXAuMikpICU+JSAjIHNlcm8rIGVxdWFscyB0byB0aGUgc3VtIG9mIGNvbXAgMSsyCiAgbXV0YXRlKGxhYmVsID0gaWZfZWxzZShjb21wLnNuID4gdSwgInMtIiwgCiAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShjb21wLnNwID4gdSwgInMrIiwgInMwIgogICAgICAgICAgICAgICAgICAgICAgICAjaWZlbHNlKGNvbXAuMiA+IHUsICJzKyIsICMiczAiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjaWZlbHNlKGNvbXAuMSA+IHUsInMrKyIsInMwIikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpKSAlPiUgCiAgbXV0YXRlKGxhYmVsPWZvcmNhdHM6OmZjdF9yZWxldmVsKGxhYmVsLCJzLSIsInMwIiwicysiIywicysrIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKSAKCnMgPC0gcG9zdC5kZiAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZmFjdG9yKGxhYmVsKSkpICsKICBnZW9tX2JhcigpICsKICB4bGFiKCJDb21wb25lbnQiKSArCiAgeWxhYigiTnVtYmVyIG9mIERhdGEgUG9pbnRzIikgKwogIGxhYnModGl0bGU9IkNsYXNzaWZpY2F0aW9uIikKCiMjIwp0IDwtIHBvc3QuZGYgJT4lIAogIGdncGxvdCgpICsKICAjZ2VvbV9saW5lKGFlcyh4LGNvbXAuMSksIGNvbG91cj0iZ3JlZW4iLCBsd2QgPSAxLjUpICsKICAjZ2VvbV9saW5lKGFlcyh4LGNvbXAuMiksIGNvbG91cj0iYmx1ZSIsIGx3ZCA9IDEuNSkgKwogICNnZW9tX3BvaW50KGFlcyh4LGNvbXAuc3ApLCBjb2xvdXI9ImJsdWUiLCBsd2QgPSAxLjUpICsKICBnZW9tX2xpbmUoYWVzKHgsY29tcC5zcCksIGNvbG91cj0iYmx1ZSIsIGx3ZCA9IDEuNSkgKwogICNnZW9tX3BvaW50KGFlcyh4LGNvbXAuc24pLCBjb2xvdXI9InJlZCIsIGx3ZCA9IDEuNSkgKwogIGdlb21fbGluZShhZXMoeCxjb21wLnNuKSwgY29sb3VyPSJyZWQiLCBsd2QgPSAxLjUpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSB1LCBjb2wgPSAiYmxhY2siKSArCiAgI2dlb21fdmxpbmUoeGludGVyY2VwdCA9IDYzLjYsIGNvbCA9ICJibGFjayIsIGx0eT0zKSArCiAgI2dlb21fdmxpbmUoeGludGVyY2VwdCA9IDY5LjcsIGNvbCA9ICJibGFjayIsIGx0eT0zKSArCiAgeGxhYigiQWIudW5pdHMiKSArCiAgeWxhYigiY2xhc3NpZmljYXRpb24gcHJvYmFiaWxpdHkiKSArCiAgbGFicyh0aXRsZT0iQ3V0b2ZmIikKCgojIyMKbXNyX3AgPC0gaW5uZXJfam9pbihtY28gJT4lCiAgICAgICAgICAgICAgICAgICAgZmlsdGVyKGlnZz09bGV2ZWxzKGYpW2ldKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgcm93bmFtZXNfdG9fY29sdW1uKCksCiAgICAgICAgICAgcG9zdC5kZiAlPiUKICAgICAgICAgICAgICNkcGx5cjo6cmVuYW1lKEFiLnVuaXRzX2xvZz14KSAlPiUgCiAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KCNBYi51bml0c19sb2csCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsKSAlPiUgCiAgICAgICAgICAgICByb3duYW1lc190b19jb2x1bW4oKSwKICAgICAgICAgICBieT0icm93bmFtZSIpICMlPiUgCiAgI211dGF0ZSh0ZXN0PSBBYi51bml0c19sb2cueD09QWIudW5pdHNfbG9nLnkpICU+JSBkcGx5cjo6Y291bnQodGVzdCkKCgptc3IgPC0gdW5pb24obXNyLCBtc3JfcCkKCgpSbWlzYzo6bXVsdGlwbG90KHIsdCxzLGNvbHMgPSAzKQogIAp9CmBgYAoKIyBEQVRBIEZSQU1FCgpgYGB7cn0KI21jbwojbXNyCmBgYAoKCmBgYHtyfQpnbGltcHNlKAogIG1zciAlPiUgCiAgbXV0YXRlKG9yZD1hcy5udW1lcmljKG9yZCkpICU+JSAgYXJyYW5nZShvcmQpICU+JSAKICBkcGx5cjo6c2VsZWN0KC1BYi51bml0c19sb2csIC1yb3duYW1lKQopCiNzdW1tYXJ5KG1kbykKcmVhZHI6OndyaXRlX2NzdigKICBtc3IgJT4lIAogIG11dGF0ZShvcmQ9YXMubnVtZXJpYyhvcmQpKSAlPiUgIGFycmFuZ2Uob3JkKSAlPiUgCiAgZHBseXI6OnNlbGVjdCgtQWIudW5pdHNfbG9nLCAtcm93bmFtZSkKICAgICAgICAgICAgICAgICAsImRhdGEvdW5hcC1yYWZhZWwuY3N2IikKcmVhZHI6OndyaXRlX3JkcygKICBtc3IgJT4lIAogIG11dGF0ZShvcmQ9YXMubnVtZXJpYyhvcmQpKSAlPiUgIGFycmFuZ2Uob3JkKSAlPiUgCiAgZHBseXI6OnNlbGVjdCgtQWIudW5pdHNfbG9nLCAtcm93bmFtZSkKICAsICJkYXRhL3VuYXAtcmFmYWVsLnJkcyIpCmBgYAoKIyBTVEFUSVNUSUNBTCBBTkFMWVNJUyBQTEFOCgojIyBUbyBEbwoKLSBEbyBpdAoKIyMgU2FtcGxlIHNpemUKCmBgYHtyfQptY28gJT4lIAogIGdyb3VwX2J5KGlnZykgJT4lIGRwbHlyOjpjb3VudChwaGVubykKYGBgCgoKIyMgVGVzdCBIeXBvdGhlc2lzCgojIyMgTWVhbiBBVQoKYGBge3IsbWVzc2FnZT1GQUxTRSxmaWcud2lkdGg9MTAsZmlnLmhlaWdodD0yLjJ9CmYgPC0gbWNvICU+JSBtdXRhdGUoaWdnPWFzLmZhY3RvcihpZ2cpKSAlPiUgLiRpZ2cKCiNtY28gPC0gbWNvICU+JSAKIyAgI2RwbHlyOjpzZWxlY3QoQWIudW5pdHMscGFyKSAlPiUgCiMgIG11dGF0ZShBYi51bml0cz1sb2cxMChBYi51bml0cykscGFyPWxvZzEwKHBhcikpICU+JSAKIyAgZmlsdGVyKHBhciE9LUluZikgIyU+JSAKCnN0dCA8LSBkYXRhX2ZyYW1lKCMjZXN0aW1hdGU9YXMuZG91YmxlKCksCiAgICAgICAgICAgICAgICAgICMjZXN0aW1hdGUxPWFzLmRvdWJsZSgpLAogICAgICAgICAgICAgICAgICAjI2VzdGltYXRlMj1hcy5kb3VibGUoKSwKICAgICAgICAgICAgICAgICAgc3RhdGlzdGljPWFzLmRvdWJsZSgpLAogICAgICAgICAgICAgICAgICBwLnZhbHVlPWFzLmRvdWJsZSgpLAogICAgICAgICAgICAgICAgICAjcGFyYW1ldGVyPWFzLmRvdWJsZSgpLCMKICAgICAgICAgICAgICAgICAgI2NvbmYubG93PWFzLmRvdWJsZSgpLCMKICAgICAgICAgICAgICAgICAgI2NvbmYuaGlnaD1hcy5kb3VibGUoKSwjCiAgICAgICAgICAgICAgICAgIG1ldGhvZD1hcy5mYWN0b3IoTlVMTCksCiAgICAgICAgICAgICAgICAgIGFsdGVybmF0aXZlPWFzLmZhY3RvcihOVUxMKSwKICAgICAgICAgICAgICAgICAgaWdnPWFzLmNoYXJhY3RlcigpLAogICAgICAgICAgICAgICAgICBsYWI9YXMuY2hhcmFjdGVyKCkpCgpmb3IgKGwgaW4gMTpsZW5ndGgobGV2ZWxzKGYpKSkgewogIAojIyBQcmltZXJvLCBQcnVlYmEgZGUgSGlww7N0ZXNpcyBwYXJhIGNvbXBhcmFyIHZhcmlhbnphczoKaSA8LSBtY28gJT4lIGZpbHRlcihpZ2c9PWxldmVscyhmKVtsXSkgJT4lIAogIHZhci50ZXN0KEFiLnVuaXRzX2xvZyB+IHBoZW5vLCBkYXRhID0gLikgJT4lIGJyb29tOjp0aWR5KCkKIyMgUnB0YTogQmFqbyBuLnMuIDAuMDUsIEYgY2FlIGVuIFJlZ2nDs24gZGUgbm8tUmVjaGF6byBkZSBIaXDDs3Rlc2lzIE51bGEgKFJub1JIbykKIyMgQ29uY2x1c2nDs246IFN1cHVlc3RvIGRlIGlndWFsZGFkIGRlIHZhcmlhbnphcyBwb2JsYWNpb25hbGVzIFPDjSBlcyB2w6FsaWRvCiMjIFNlZ3VuZG8sIFBydWViYSBkZSBIaXDDs3Rlc2lzIHBhcmEgY29tcGFyYXIgbWVkaWFzOgpqIDwtIG1jbyAlPiUgZmlsdGVyKGlnZz09bGV2ZWxzKGYpW2xdKSAlPiUgCiAgI3QudGVzdChBYi51bml0c19sb2cgfiBwaGVubywgZGF0YSA9IC4sIHZhci5lcXVhbD0gaSRwLnZhbHVlPjAuMDUpICU+JQogICN3aWxjb3gudGVzdChBYi51bml0c19sb2cgfiBwaGVubywgZGF0YSA9IC4pICU+JSMsIAogIHdpbGNveC50ZXN0KEFiLnVuaXRzIH4gcGhlbm8sIGRhdGEgPSAuKSAlPiUjLCAKICAgICAgICAgICAgICAjY29uZi5pbnQ9VFJVRSkgJT4lIAogIGJyb29tOjp0aWR5KCkgJT4lICAjJT4lIGZvcm1hdChkaWdpdHM9MikKICBkcGx5cjo6c2VsZWN0KC1zdGFydHNfd2l0aCgiZXN0aW1hdGUiKSkgJT4lIAogIG11dGF0ZShpZ2c9bGV2ZWxzKGYpW2xdLAogICAgICAgICBsYWI9IHBhc3RlMCgjInQ9Iiwjc2hvdWxkIGJlIGRvbmUgLT4gbWl4IHZhcmlhbmNlIGVxdWFsaXR5IHRlc3QKICAgICAgICAgICAgICAgICAgICAgIyJXPSIsI25vbi1wYXJhbWV0cmljIHVzZWQgaW4gbGl0ZXJhdHVyZQogICAgICAgICAgICAgICAgICAgICAjc3RhdGlzdGljICU+JSBmb3JtYXQoZGlnaXRzPTIpLAogICAgICAgICAgICAgICAgICAgICAjIiwgZGY9IixwYXJhbWV0ZXIgJT4lIGZvcm1hdChkaWdpdHM9MiksCiAgICAgICAgICAgICAgICAgICAgICMiLCBQIixpZmVsc2UocC52YWx1ZTwwLjAwMSwiPDAuMDAxIiwKICAgICAgICAgICAgICAgICAgICAgIml0YWxpYygnUCcpIixpZmVsc2UocC52YWx1ZTwwLjAwMSwiPDAuMDAxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlMCgiPT0iLHAudmFsdWUgJT4lIGZvcm1hdChkaWdpdHM9MikpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgKQoKc3R0IDwtIHN0dCAlPiUgdW5pb24oaikKCn0KCnN0dCA8LSBzdHQgJT4lIGFycmFuZ2UoaWdnKSAlPiUgZHBseXI6OnNlbGVjdChpZ2csZXZlcnl0aGluZygpKSAlPiUgCiAgbXV0YXRlKHg9LjUsCiAgICAgICAgIHk9LjE1KSAlPiUgCiAgbXV0YXRlKGlnZz1mb3JjYXRzOjpmY3RfcmVjb2RlKGlnZywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklnRyI9ImlnZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJZ0cxIj0iaWdnMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJZ0cyIj0iaWdnMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJZ0czIj0iaWdnMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJZ0c0Ij0iaWdnNCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkKCiMgcGxvdAptY28gJT4lICNmaWx0ZXIoaWdnPT1sZXZlbHMoZilbMV0pICU+JSAKICBtdXRhdGUoaWdnPWZvcmNhdHM6OmZjdF9yZWNvZGUoaWdnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSWdHIj0iaWdnIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklnRzEiPSJpZ2cxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklnRzIiPSJpZ2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklnRzMiPSJpZ2czIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklnRzQiPSJpZ2c0IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICBwaGVubz1mb3JjYXRzOjpmY3RfcmVjb2RlKHBoZW5vLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBc3ltcHRvbWF0aWMiPSJhc3ltcHRvbWF0aWMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTeW1wdG9tYXRpYyI9InN5bXB0b21hdGljIikpICU+JQogIGdncGxvdChhZXMocGhlbm8sQWIudW5pdHMpKSArCiAgZ2VvbV9ib3hwbG90KCNwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSgwLjgpCiAgKSArCiAgZ2VvbV9kb3RwbG90KCNhZXMoZmlsbD1zZXZfV0hPKSwgCiAgICBiaW5heGlzPSd5Jywgc3RhY2tkaXI9J2NlbnRlcicsIGFscGhhPS4zLCAKICAgIGRvdHNpemU9MSMsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKDAuOCkKICApICsKICAKICBmYWNldF93cmFwKH5pZ2csbmNvbCA9IDUpICsgCiAgCiAgZ2VvbV90ZXh0KGFlcyh4LHksbGFiZWw9bGFiKSxkYXRhID0gc3R0LHBhcnNlID0gVCwKICAgICAgICAgICAgI3ZqdXN0PS41LGhqdXN0PTAuMDUsc2l6ZT0zLjUpICsKICAgICAgICAgICAgdmp1c3Q9LjUsaGp1c3Q9MC4wNSxzaXplPTMuNSkgKyAjIGlmIGxvZzEwLCB0aGVuIGNoYW5nZSBpdC4KICAKICAjY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0zMDAsMjAwMCkpICsgIyBpZiBsb2cxMCwgdGhlbiBjaGFuZ2UgaXQuCiAgc2NhbGVfeV9sb2cxMCgpICsKICAKICAjbGFicyh0aXRsZT0iVGVzdCBBVSBtZWFuIGVxdWFsaXR5IGFtb25nIHBoZW5vdHlwZXMgcGVyIElnRyBzdWJ0eXBlcyIpICsKICB4bGFiKCJDYXJyaWVyIikgKyB5bGFiKCJBbnRpYm9keSB1bml0cyAobG9nIHNjYWxlKSIpCmBgYAoKLSBub3RhOgogICAgKyBwcnVlYmEgZGUgaGlwb3Rlc2lzIG5vLXBhcmFtw6l0cmljYQogICAgKyBwbG90ZW8gZW4gZXNjYWxhIGxvZ8Otc3RpY2EKCmBgYHtyfQptc3IgJT4lIGdyb3VwX2J5KGlnZyxwaGVubykgJT4lIGRwbHlyOjpzdW1tYXJpc2UobWluPW1pbihBYi51bml0cyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHEyNT1xdWFudGlsZShBYi51bml0cykgJT4lIC5bMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYW49bWVhbihBYi51bml0cyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHE1MD1xdWFudGlsZShBYi51bml0cykgJT4lIC5bM10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHE3NT1xdWFudGlsZShBYi51bml0cykgJT4lIC5bNF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heD1tYXgoQWIudW5pdHMpKQpgYGAKCiMjIyBQcm9wb3J0aW9uIHNlcm8rCgpgYGB7cn0KbXNyICU+JSBkcGx5cjo6Y291bnQoaWdnLGxhYmVsKSAlPiUgCiAgZ3JvdXBfYnkoaWdnKSAlPiUgbXV0YXRlKHRvdD1zdW0obikscHJvcD0gKG4qMTAwKS8oc3VtKG4pKSkgJT4lIAogIGZpbHRlcihsYWJlbD09InMrIikKYGBgCgpgYGB7cixmaWcud2lkdGg9NS4yNSxmaWcuaGVpZ2h0PTIuNX0KbXNyICU+JSAKICBtdXRhdGUobGFiZWw9Zm9yY2F0czo6ZmN0X3JlbGV2ZWwobGFiZWwsInMtIiwicysiLCJzMCIjLCJzKysiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpICU+JSAKICBnZ3Bsb3QoYWVzKHg9aWdnLGZpbGw9bGFiZWwpKSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIpICsKICAjZmFjZXRfZ3JpZCh+aWdnKSArCiAgbGFicyh0aXRsZT0iUHJvcG9ydGlvbiBvZiBzZXJvcG9zaXRpdmVzIHBlciBJZ0cgc3VidHlwZSIpCmBgYAoKYGBge3J9Cm1zciAlPiUgZHBseXI6OmNvdW50KGlnZyxwaGVubyxsYWJlbCkgJT4lIAogIGdyb3VwX2J5KGlnZyxwaGVubykgJT4lIG11dGF0ZSh0b3Q9c3VtKG4pLHByb3A9IChuKjEwMCkvKHN1bShuKSkpICU+JSAKICBmaWx0ZXIobGFiZWw9PSJzKyIpICMlPiUgCiAgI3VuZ3JvdXAoKSAlPiUgCiAgI2RwbHlyOjpzZWxlY3QoLW4sLWxhYmVsLCAtdG90KSAlPiUgCiAgI3NwcmVhZChwaGVubyxwcm9wKQpgYGAKCmBgYHtyfQptc3IgJT4lIAogIGRwbHlyOjpzZWxlY3QocGhlbm8saWdnLGxhYmVsKSAlPiUgCiAgI2ZpbHRlcihpZ2c9PWxldmVscyhmKVtpXSkgJT4lIAogICNkcGx5cjo6c2VsZWN0KC1pZ2cpICU+JSAKICBncm91cF9ieShpZ2cscGhlbm8sbGFiZWwpICU+JSBkcGx5cjo6c3VtbWFyaXNlKG49bigpKSAlPiUgdW5ncm91cCgpICU+JSAKICBzcHJlYWQobGFiZWwsbikKYGBgCgoKYGBge3J9CmZ0dCA8LSBkYXRhX2ZyYW1lKGlnZz1hcy5jaGFyYWN0ZXIoKSwKICAgICAgICAgICAgICAgICAgcC52YWx1ZT1hcy5kb3VibGUoKSwKICAgICAgICAgICAgICAgICAgI2VzdGltYXRlPWFzLmRvdWJsZSgpLAogICAgICAgICAgICAgICAgICBtZXRob2Q9YXMuY2hhcmFjdGVyKCkjLAogICAgICAgICAgICAgICAgICAjYWx0ZXJuYXRpdmU9YXMuZmFjdG9yKCkKICAgICAgICAgICAgICAgICAgKQoKCmZvciAoaSBpbiAxOmxlbmd0aChsZXZlbHMoZikpKSB7CiAgCmZzdCA8LSBtc3IgJT4lIAogIGZpbHRlcighbGFiZWw9PSJzMCIpICU+JSAKICBkcGx5cjo6c2VsZWN0KHBoZW5vLGlnZyxsYWJlbCkgJT4lIAogIGZpbHRlcihpZ2c9PWxldmVscyhmKVtpXSkgJT4lIAogIGRwbHlyOjpzZWxlY3QoLWlnZykgJT4lIAogIGdyb3VwX2J5KHBoZW5vLGxhYmVsKSAlPiUgZHBseXI6OnN1bW1hcmlzZShuPW4oKSkgJT4lIHVuZ3JvdXAoKSAlPiUgCiAgI3NwcmVhZChsYWJlbCxuKSAlPiUgYXMubWF0cml4KCkgJT4lIAogIHJlc2hhcGUyOjphY2FzdChwaGVubyB+IGxhYmVsLAogICAgICAgICAgICAgICAgICB2YWx1ZS52YXIgPSAibiIpICMlPiUgI2NsYXNzKCkKCmZzdFtpcy5uYShmc3QpXSA8LSAwCgpmdHQgPC0gZnR0ICU+JSAKICB1bmlvbigKICBmaXNoZXIudGVzdChmc3QpICU+JSBicm9vbTo6dGlkeSgpICU+JSAKICAgIG11dGF0ZShpZ2c9bGV2ZWxzKGYpW2ldKSAlPiUgCiAgICBkcGx5cjo6c2VsZWN0KGlnZyxwLnZhbHVlLAogICAgICAgICAgICAgICAgICAjZXN0aW1hdGUsCiAgICAgICAgICAgICAgICAgIG1ldGhvZCMsYWx0ZXJuYXRpdmUKICAgICAgICAgICAgICAgICAgKQopCgoKICAKfQoKZnR0ICU+JSBhcnJhbmdlKGlnZykgJT4lIAogIG11dGF0ZShzaWc9aWZlbHNlKHAudmFsdWU8MC4wNSwic2lnbmlmIiwibm90LXNpZ25pZiIpKQpgYGAKCmBgYHtyfQpmdHR0IDwtIGZ0dCAlPiUgYXJyYW5nZShpZ2cpICU+JSBkcGx5cjo6c2VsZWN0KGlnZyxldmVyeXRoaW5nKCkpICU+JSAKICBtdXRhdGUoeD0uNSwKICAgICAgICAgeT0tLjA1KSAlPiUgCiAgbXV0YXRlKGxhYj0gcGFzdGUwKCJpdGFsaWMoJ1AnKSIsaWZlbHNlKHAudmFsdWU8MC4wMDEsIjwwLjAwMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZTAoIj09IixwLnZhbHVlICU+JSBmb3JtYXQoZGlnaXRzPTIpKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICkgJT4lIAogIG11dGF0ZShsYWI9c3RyaW5ncjo6c3RyX3JlcGxhY2UobGFiLCIoUCA9IDBcXC4uLikoLispIiwiXFwxIikpICU+JSAKICBtdXRhdGUoaWdnPWZvcmNhdHM6OmZjdF9yZWNvZGUoaWdnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSWdHIj0iaWdnIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklnRzEiPSJpZ2cxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklnRzIiPSJpZ2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklnRzMiPSJpZ2czIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklnRzQiPSJpZ2c0IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKQpgYGAKCmBgYHtyLGZpZy53aWR0aD0xMSxmaWcuaGVpZ2h0PTIuMn0KbXNyICU+JSAKICBtdXRhdGUoaWdnPWZvcmNhdHM6OmZjdF9yZWNvZGUoaWdnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSWdHIj0iaWdnIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklnRzEiPSJpZ2cxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklnRzIiPSJpZ2cyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklnRzMiPSJpZ2czIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklnRzQiPSJpZ2c0IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApLAogICAgICAgICBwaGVubz1mb3JjYXRzOjpmY3RfcmVjb2RlKHBoZW5vLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBc3ltcHRvbWF0aWMiPSJhc3ltcHRvbWF0aWMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTeW1wdG9tYXRpYyI9InN5bXB0b21hdGljIikpICU+JQogIG11dGF0ZShsYWJlbD1mb3JjYXRzOjpmY3RfcmVsZXZlbChsYWJlbCwicy0iLCJzKyIsInMwIiMsInMrKyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkgJT4lIAogIGZ1bGxfam9pbihmdHR0ICU+JSBkcGx5cjo6c2VsZWN0KGlnZyxsYWIseSx4KSxieSA9ICJpZ2ciKSAlPiUgCiAgbXV0YXRlKGxhYj1pZl9lbHNlKGxhYmVsPT0icysiLGxhYixOQV9jaGFyYWN0ZXJfKSkgJT4lIAogIGFycmFuZ2UobGFiKSAlPiUgCiAgbXV0YXRlKGxhYj1pZl9lbHNlKGlnZz09bGVhZChpZ2cpLE5BX2NoYXJhY3Rlcl8sbGFiKSkgJT4lIAogIGZpbHRlcighbGFiZWw9PSJzMCIpICU+JSAKICBnZ3Bsb3QoYWVzKHg9cGhlbm8sZmlsbD1sYWJlbCkpICsKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIikgKwogIGZhY2V0X2dyaWQofmlnZykgKwogIAogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygtLjEyLDEpKSArCiAgZ2VvbV90ZXh0KGFlcyh4PXgsCiAgICAgICAgICAgICAgICB5PXksbGFiZWw9bGFiKSxwYXJzZSA9IFQsI3Bvc2l0aW9uID0gImZpbGwiLCNkYXRhID0gZnR0dCwsCiAgICAgICAgICAgICMjdmp1c3Q9LjUsaGp1c3Q9MC4wNSxzaXplPTMuNSkgKwogICAgICAgICAgICB2anVzdD0xLGhqdXN0PTAuMDAwNSxzaXplPTMuNQogICAgICAgICAgICApICsgIyBpZiBsb2cxMCwgdGhlbiBjaGFuZ2UgaXQuCiAgCiAgI2xhYnModGl0bGU9IlByb3BvcnRpb24gb2Ygc2Vyb3Bvc2l0aXZlcyBhbW9uZyBwaGVub3R5cGVzIHBlciBJZ0cgc3VidHlwZSIpICsKICB4bGFiKCJDYXJyaWVyIikgKyB5bGFiKCJQcm9wb3J0aW9uIikgKwogIHNjYWxlX2ZpbGxfZ3JleSgjc3RhcnQgPSAwLCBlbmQgPSAuOSwKICAgICAgICAgICAgICAgICAgbmFtZT0iU2Vyb2xvZ3kiLGxhYmVscz1jKCJOZWdhdGl2ZSIsIlBvc2l0aXZlIiMsIkluZGV0ZXJtaW5hdGUiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKQpgYGAKCmBgYHtyfQojI2FxdWkKczEgPC0gSG1pc2M6OnN1bW1hcnlNKGxhYmVsCiAgICAgICAgICAgICAgICAgICAgICB+IHBoZW5vLAogICAgICAgICAgICAgICBkYXRhPW1zciAlPiUgZmlsdGVyKGlnZz09ImlnZyIpLAogICAgICAgICAgICAgICBvdmVyYWxsPUZBTFNFLCB0ZXN0PVRSVUUpCgpIbWlzYzo6bGF0ZXgoczEsIGNhcHRpb249J1NhbXBsZSBjb3ZhcmlhdGVzJywKICAgICAgZXhjbHVkZTE9VFJVRSwgbnBjdD0nYm90aCcsIAogICAgICBkaWdpdHM9MywKICAgICAgI3BybXNkPVRSVUUsIGJybXNkPVRSVUUsICNtc2RzaXplPW11JHNtYWxsZXIyLCAjTk9ULUVWQUxVQVRFIGlmIFBERgogICAgICBtaWRkbGUuYm9sZD1UUlVFLCBsb25nID0gVFJVRSwKICAgICAgI2xlZ2VuZC5ib3R0b20gPSBUUlVFLCAjaW5zZXJ0LmJvdHRvbSA9IFRSVUUsIAogICAgICB3aGF0PSIlIiwgaHRtbCA9IFRSVUUsIHdpZHRoPSIxMDAlIgogICAgICApICNjaGFuZ2UgaGVyZSBmb3IgTGFUZVggUERGCmBgYApgYGB7cn0KIyNhcXVpCnMxIDwtIEhtaXNjOjpzdW1tYXJ5TShsYWJlbAogICAgICAgICAgICAgICAgICAgICAgfiBwaGVubywKICAgICAgICAgICAgICAgZGF0YT1tc3IgJT4lIGZpbHRlcihpZ2c9PSJpZ2cxIiksCiAgICAgICAgICAgICAgIG92ZXJhbGw9RkFMU0UsIHRlc3Q9VFJVRSkKCkhtaXNjOjpsYXRleChzMSwgY2FwdGlvbj0nU2FtcGxlIGNvdmFyaWF0ZXMnLAogICAgICBleGNsdWRlMT1UUlVFLCBucGN0PSdib3RoJywgCiAgICAgIGRpZ2l0cz0zLAogICAgICAjcHJtc2Q9VFJVRSwgYnJtc2Q9VFJVRSwgI21zZHNpemU9bXUkc21hbGxlcjIsICNOT1QtRVZBTFVBVEUgaWYgUERGCiAgICAgIG1pZGRsZS5ib2xkPVRSVUUsIGxvbmcgPSBUUlVFLAogICAgICAjbGVnZW5kLmJvdHRvbSA9IFRSVUUsICNpbnNlcnQuYm90dG9tID0gVFJVRSwgCiAgICAgIHdoYXQ9IiUiLCBodG1sID0gVFJVRSwgd2lkdGg9IjEwMCUiCiAgICAgICkgI2NoYW5nZSBoZXJlIGZvciBMYVRlWCBQREYKYGBgCgpgYGB7cn0KIyNhcXVpCnMxIDwtIEhtaXNjOjpzdW1tYXJ5TShsYWJlbAogICAgICAgICAgICAgICAgICAgICAgfiBwaGVubywKICAgICAgICAgICAgICAgZGF0YT1tc3IgJT4lIGZpbHRlcihpZ2c9PSJpZ2cyIiksCiAgICAgICAgICAgICAgIG92ZXJhbGw9RkFMU0UsIHRlc3Q9VFJVRSkKCkhtaXNjOjpsYXRleChzMSwgY2FwdGlvbj0nU2FtcGxlIGNvdmFyaWF0ZXMnLAogICAgICBleGNsdWRlMT1UUlVFLCBucGN0PSdib3RoJywgCiAgICAgIGRpZ2l0cz0zLAogICAgICAjcHJtc2Q9VFJVRSwgYnJtc2Q9VFJVRSwgI21zZHNpemU9bXUkc21hbGxlcjIsICNOT1QtRVZBTFVBVEUgaWYgUERGCiAgICAgIG1pZGRsZS5ib2xkPVRSVUUsIGxvbmcgPSBUUlVFLAogICAgICAjbGVnZW5kLmJvdHRvbSA9IFRSVUUsICNpbnNlcnQuYm90dG9tID0gVFJVRSwgCiAgICAgIHdoYXQ9IiUiLCBodG1sID0gVFJVRSwgd2lkdGg9IjEwMCUiCiAgICAgICkgI2NoYW5nZSBoZXJlIGZvciBMYVRlWCBQREYKYGBgCgpgYGB7cn0KIyNhcXVpCnMxIDwtIEhtaXNjOjpzdW1tYXJ5TShsYWJlbAogICAgICAgICAgICAgICAgICAgICAgfiBwaGVubywKICAgICAgICAgICAgICAgZGF0YT1tc3IgJT4lIGZpbHRlcihpZ2c9PSJpZ2czIiksCiAgICAgICAgICAgICAgIG92ZXJhbGw9RkFMU0UsIHRlc3Q9VFJVRSkKCkhtaXNjOjpsYXRleChzMSwgY2FwdGlvbj0nU2FtcGxlIGNvdmFyaWF0ZXMnLAogICAgICBleGNsdWRlMT1UUlVFLCBucGN0PSdib3RoJywgCiAgICAgIGRpZ2l0cz0zLAogICAgICAjcHJtc2Q9VFJVRSwgYnJtc2Q9VFJVRSwgI21zZHNpemU9bXUkc21hbGxlcjIsICNOT1QtRVZBTFVBVEUgaWYgUERGCiAgICAgIG1pZGRsZS5ib2xkPVRSVUUsIGxvbmcgPSBUUlVFLAogICAgICAjbGVnZW5kLmJvdHRvbSA9IFRSVUUsICNpbnNlcnQuYm90dG9tID0gVFJVRSwgCiAgICAgIHdoYXQ9IiUiLCBodG1sID0gVFJVRSwgd2lkdGg9IjEwMCUiCiAgICAgICkgI2NoYW5nZSBoZXJlIGZvciBMYVRlWCBQREYKYGBgCgpgYGB7cn0KIyNhcXVpCnMxIDwtIEhtaXNjOjpzdW1tYXJ5TShsYWJlbAogICAgICAgICAgICAgICAgICAgICAgfiBwaGVubywKICAgICAgICAgICAgICAgZGF0YT1tc3IgJT4lIGZpbHRlcihpZ2c9PSJpZ2c0IiksCiAgICAgICAgICAgICAgIG92ZXJhbGw9RkFMU0UsIHRlc3Q9VFJVRSkKCkhtaXNjOjpsYXRleChzMSwgY2FwdGlvbj0nU2FtcGxlIGNvdmFyaWF0ZXMnLAogICAgICBleGNsdWRlMT1UUlVFLCBucGN0PSdib3RoJywgCiAgICAgIGRpZ2l0cz0zLAogICAgICAjcHJtc2Q9VFJVRSwgYnJtc2Q9VFJVRSwgI21zZHNpemU9bXUkc21hbGxlcjIsICNOT1QtRVZBTFVBVEUgaWYgUERGCiAgICAgIG1pZGRsZS5ib2xkPVRSVUUsIGxvbmcgPSBUUlVFLAogICAgICAjbGVnZW5kLmJvdHRvbSA9IFRSVUUsICNpbnNlcnQuYm90dG9tID0gVFJVRSwgCiAgICAgIHdoYXQ9IiUiLCBodG1sID0gVFJVRSwgd2lkdGg9IjEwMCUiCiAgICAgICkgI2NoYW5nZSBoZXJlIGZvciBMYVRlWCBQREYKYGBgCgo8IS0tIC0tPgoKYGBge3IsZXZhbD1GQUxTRSwgZWNobz1GQUxTRX0KVGVhVGFzdGluZyA8LQptYXRyaXgoYygzLCAxLCAxLCAzKSwKICAgICAgIG5yb3cgPSAyLAogICAgICAgZGltbmFtZXMgPSBsaXN0KEd1ZXNzID0gYygiTWlsayIsICJUZWEiKSwKICAgICAgICAgICAgICAgICAgICAgICBUcnV0aCA9IGMoIk1pbGsiLCAiVGVhIikpKQpmaXNoZXIudGVzdChUZWFUYXN0aW5nLCBhbHRlcm5hdGl2ZSA9ICJncmVhdGVyIikKIyMgPT4gcCA9IDAuMjQyOSwgYXNzb2NpYXRpb24gY291bGQgbm90IGJlIGVzdGFibGlzaGVkCgpKb2IgPC0gbWF0cml4KGMoMSwyLDEsMCwgMywzLDYsMSwgMTAsMTAsMTQsOSwgNiw3LDEyLDExKSwgNCwgNCwKZGltbmFtZXMgPSBsaXN0KGluY29tZSA9IGMoIjwgMTVrIiwgIjE1LTI1ayIsICIyNS00MGsiLCAiPiA0MGsiKSwKICAgICAgICAgICAgICAgIHNhdGlzZmFjdGlvbiA9IGMoIlZlcnlEIiwgIkxpdHRsZUQiLCAiTW9kZXJhdGVTIiwgIlZlcnlTIikpKQpmaXNoZXIudGVzdChKb2IpCmZpc2hlci50ZXN0KEpvYiwgc2ltdWxhdGUucC52YWx1ZSA9IFRSVUUsIEIgPSAxZTUpCgpjbGFzcyhKb2IpCmBgYAoKCiMjIyBEaXN0cmlidXRpb24gc2VybysKCi0gdGhlIF9fbWluaW11bV9fIHZhbHVlIG9mIHRoZSBfX3Nlcm8rX18gZGlzdHJpYnV0aW9uIGlzIGNsb3NlIHRvIHRoZSBfX2N1dC1vZmZfXyBhbmQgY291bGQgYmUgYXNzdW1lZCBhcyBpdHMgdmFsdWUsIGJ1dCBpcyBub3QgZXhhY3RseSB0aGF0IHZhbHVlLgoKYGBge3IsZmlnLndpZHRoPTEwLjUsZmlnLmhlaWdodD0yLjV9Cm1zciAlPiUgCiAgbXV0YXRlKGxhYmVsPWZvcmNhdHM6OmZjdF9yZWxldmVsKGxhYmVsLCJzLSIsInMrIiwiczAiIywicysrIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKSAlPiUgCiAgZ2dwbG90KGFlcyh4PUFiLnVuaXRzLGZpbGw9bGFiZWwpKSArCiAgI2dlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiKSArCiAgZ2VvbV9oaXN0b2dyYW0ocG9zaXRpb24gPSAic3RhY2siKSArCiAgZmFjZXRfZ3JpZCh+aWdnLHNjYWxlcyA9ICJmcmVlIikgKwogIGxhYnModGl0bGU9IlByb3BvcnRpb24gb2Ygc2Vyb3Bvc2l0aXZlcyIpCmBgYAoKYGBge3J9Cm1zciAlPiUgCiAgZmlsdGVyKGxhYmVsPT0icysiKSAlPiUgCiAgZ3JvdXBfYnkoaWdnKSAlPiUgZHBseXI6OnN1bW1hcmlzZShtaW49bWluKEFiLnVuaXRzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcTI1PXF1YW50aWxlKEFiLnVuaXRzKSAlPiUgLlsyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhbj1tZWFuKEFiLnVuaXRzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcTUwPXF1YW50aWxlKEFiLnVuaXRzKSAlPiUgLlszXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcTc1PXF1YW50aWxlKEFiLnVuaXRzKSAlPiUgLls0XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4PW1heChBYi51bml0cykpCmBgYAoKYGBge3IsZmlnLndpZHRoPTEwLjUsZmlnLmhlaWdodD00fQptc3IgJT4lIAogIG11dGF0ZShsYWJlbD1mb3JjYXRzOjpmY3RfcmVsZXZlbChsYWJlbCwicy0iLCJzKyIsInMwIiMsInMrKyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkgJT4lIAogIGdncGxvdChhZXMoeD1BYi51bml0cyxmaWxsPWxhYmVsKSkgKwogICNnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIikgKwogICNzY2FsZV94X2xvZzEwKCkgKwogIGdlb21faGlzdG9ncmFtKHBvc2l0aW9uID0gInN0YWNrIikgKwogIGZhY2V0X2dyaWQocGhlbm9+aWdnLHNjYWxlcyA9ICJmcmVlIikgKwogIGxhYnModGl0bGU9IlByb3BvcnRpb24gb2Ygc2Vyb3Bvc2l0aXZlcyIpCmBgYAoKIyMgQ29ycmVsYXRpb24KCiMjIyBJZ0cgc3VidHlwZXMKCmBgYHtyLGZpZy5oZWlnaHQ9NCxmaWcud2lkdGg9Nn0KbWNvICU+JSBkaW0oKQoKdSA8LSBtY28gJT4lIGZpbHRlcihwaGVubz09ImFzeW1wdG9tYXRpYyIpICU+JSAKICBkcGx5cjo6c2VsZWN0KElELGlnZyxBYi51bml0cykgJT4lIAogICNtdXRhdGUoQWIudW5pdHM9bG9nMTAoQWIudW5pdHMpKSAlPiUgCiAgc3ByZWFkKGlnZyxBYi51bml0cykgJT4lIAogIGRwbHlyOjpzZWxlY3QoLUlEKSAlPiUgCiAgbXV0YXRlKHBoZW5vPSJhc3ltcHRvbWF0aWMiKSAlPiUgCiAgbXV0YXRlKHBoZW5vPWZvcmNhdHM6OmZjdF9yZWNvZGUocGhlbm8sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFzeW1wdG9tYXRpYyI9ImFzeW1wdG9tYXRpYyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlN5bXB0b21hdGljIj0ic3ltcHRvbWF0aWMiKSkgJT4lCiAgZHBseXI6OnJlbmFtZSgiSWdHIj0iaWdnIiwiSWdHMSI9ImlnZzEiLAogICAgICAgICAgICAgICAgIklnRzIiPSJpZ2cyIiwiSWdHMyI9ImlnZzMiLCJJZ0c0Ij0iaWdnNCIpCgp2IDwtIG1jbyAlPiUgZmlsdGVyKHBoZW5vPT0ic3ltcHRvbWF0aWMiKSAlPiUgCiAgZHBseXI6OnNlbGVjdChJRCxpZ2csQWIudW5pdHMpICU+JSAKICAjbXV0YXRlKEFiLnVuaXRzPWxvZzEwKEFiLnVuaXRzKSkgJT4lIAogIHNwcmVhZChpZ2csQWIudW5pdHMpICU+JSAKICBkcGx5cjo6c2VsZWN0KC1JRCkgJT4lIAogIG11dGF0ZShwaGVubz0ic3ltcHRvbWF0aWMiKSAlPiUgCiAgbXV0YXRlKHBoZW5vPWZvcmNhdHM6OmZjdF9yZWNvZGUocGhlbm8sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFzeW1wdG9tYXRpYyI9ImFzeW1wdG9tYXRpYyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlN5bXB0b21hdGljIj0ic3ltcHRvbWF0aWMiKSkgJT4lCiAgZHBseXI6OnJlbmFtZSgiSWdHIj0iaWdnIiwiSWdHMSI9ImlnZzEiLAogICAgICAgICAgICAgICAgIklnRzIiPSJpZ2cyIiwiSWdHMyI9ImlnZzMiLCJJZ0c0Ij0iaWdnNCIpCgojcGFyKG1mcm93PWMoMSwzKSkKCmEgPC0gdW5pb24odSx2KSAlPiUgCiAgZHBseXI6OnNlbGVjdCgtcGhlbm8pIAphICU+JSAKICBQZXJmb3JtYW5jZUFuYWx5dGljczo6Y2hhcnQuQ29ycmVsYXRpb24obWV0aG9kID0gInNwZWFybWFuIixtYWluPSJhbGwiLGhpc3RvZ3JhbSA9IEYpCgpiIDwtIHVuaW9uKHUsdikgJT4lIAogIGZpbHRlcihwaGVubz09IkFzeW1wdG9tYXRpYyIpICU+JSAKICBkcGx5cjo6c2VsZWN0KC1waGVubykgCgpiICU+JSAKICBQZXJmb3JtYW5jZUFuYWx5dGljczo6Y2hhcnQuQ29ycmVsYXRpb24obWV0aG9kID0gInNwZWFybWFuIixtYWluPSJhc3ltcHRvbWF0aWMiLGhpc3RvZ3JhbSA9IEYpCgpjIDwtIHVuaW9uKHUsdikgJT4lIAogIGZpbHRlcihwaGVubz09IlN5bXB0b21hdGljIikgJT4lIAogIGRwbHlyOjpzZWxlY3QoLXBoZW5vKSAKCmMgJT4lIAogIFBlcmZvcm1hbmNlQW5hbHl0aWNzOjpjaGFydC5Db3JyZWxhdGlvbihtZXRob2QgPSAic3BlYXJtYW4iLG1haW49InN5bXB0b21hdGljIixoaXN0b2dyYW0gPSBGKQoKI2EKCiNwYXIobWZyb3c9YygxLDEpKQpgYGAKCmBgYHtyfQojZCA8LSBjCiNkIDwtIGIKI2QgPC0gYwojY29yKGRbd2hpY2goY29tcGxldGUuY2FzZXMoZCkpLF0sbWV0aG9kID0gInNwZWFybWFuIikKCmNvci5leHQgPC0gZnVuY3Rpb24oZCkgeyNkIDwtIGEKCmUgPC0gSG1pc2M6OnJjb3JyKGFzLm1hdHJpeChkW3doaWNoKGNvbXBsZXRlLmNhc2VzKGQpKSxdKSwgdHlwZT0ic3BlYXJtYW4iKQojZQpyciA8LSBlJHIgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgbXV0YXRlX2FsbChmdW5zKGlmX2Vsc2UoLj09MSxOQV9yZWFsXywuKSkpICU+JSAKICBnYXRoZXIoaWcsdmwpICU+JSBtdXRhdGUodmw9Zm9ybWF0KHZsLGRpZ2l0cyA9IDIpKSAlPiUgbXV0YXRlKHZsPWFzLm51bWVyaWModmwpKSAlPiUgCiAgZ3JvdXBfYnkoaWcpICU+JSAKICBtdXRhdGUoaWQ9MTpuKCkpICU+JSAKICBzcHJlYWQoaWcsdmwpICU+JSBkcGx5cjo6c2VsZWN0KC1pZCkgJT4lIHJvd25hbWVzX3RvX2NvbHVtbigpICMlPiUgZHBseXI6OnNlbGVjdCgtcm93bmFtZSkKcHAgPC0gZSRQICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIG11dGF0ZV9hbGwoZnVucyhpZl9lbHNlKC48MC4wMDEsMTExLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZfZWxzZSguPDAuMDEsMTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmX2Vsc2UoLjwwLjA1LDEsMCkpKSkpICU+JSAKICBtdXRhdGVfYWxsKGFzLmNoYXJhY3RlcikgJT4lIAogIG11dGF0ZV9hbGwoZnVucyhpZl9lbHNlKC49PSIxMTEiLCIoKioqKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgaWZfZWxzZSguPT0iMTEiLCIoKiopIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmX2Vsc2UoLj09IjEiLCIoKikiLCIobnMpIikpKSkpICU+JSByb3duYW1lc190b19jb2x1bW4oKQoKZWUgPC0gcnIgJT4lIGdhdGhlcihpZyx2bCkgJT4lIG11dGF0ZSh2bD0iIikgJT4lIGdyb3VwX2J5KGlnKSAlPiUgbXV0YXRlKGlkPTE6bigpKSAlPiUgc3ByZWFkKGlnLHZsKSAlPiUgZHBseXI6OnNlbGVjdCgtaWQpICU+JSBkcGx5cjo6c2VsZWN0KHJvd25hbWUsZXZlcnl0aGluZygpKQoKcHBwIDwtIGFzLm1hdHJpeChwcCkKcnJyIDwtIGFzLm1hdHJpeChycikKZWVlIDwtIGFzLm1hdHJpeChlZSkKCiNlZWUgPC0gcnJyCgplZWVbMSwzXSA8LSBwYXN0ZShycnJbMSwzXSxwcHBbMSwzXSkKZWVlWzE6Miw0XSA8LSBwYXN0ZShycnJbMToyLDRdLHBwcFsxOjIsNF0pCiNlZWVbMiw0XSA8LSBwYXN0ZShycnJbMiw0XSxwcHBbMiw0XSkKZWVlWzE6Myw1XSA8LSBwYXN0ZShycnJbMTozLDVdLHBwcFsxOjMsNV0pCiNlZWVbMiw1XSA8LSBwYXN0ZShycnJbMiw1XSxwcHBbMiw1XSkKI2VlZVszLDVdIDwtIHBhc3RlKHJyclszLDVdLHBwcFszLDVdKQplZWVbMTo0LDZdIDwtIHBhc3RlKHJyclsxOjQsNl0scHBwWzE6NCw2XSkKZXh0IDwtIGVlZSAlPiUgYXNfZGF0YV9mcmFtZSgpICU+JSBtdXRhdGUocm93bmFtZT1jb2xuYW1lcyguKVstMV0pICMlPiUgI2FzLm1hdHJpeCgpCiAgI2RwbHlyOjpyZW5hbWUoInN1YnR5cGUiPXJvd25hbWUpCnJldHVybihleHQpCiAgCn0KCmFhIDwtIGNvci5leHQoYSkgJT4lICNkcGx5cjo6cmVuYW1lKCJhbGwiPXJvd25hbWUpICU+JSAKICBjb2x1bW5fdG9fcm93bmFtZXMoKSAlPiUgYXMubWF0cml4KCkgIyU+JSBrbml0cjo6a2FibGUoZm9ybWF0ID0gImxhdGV4IikKYmIgPC0gY29yLmV4dChiKSAlPiUgI2RwbHlyOjpyZW5hbWUoImFzeW1wdCI9cm93bmFtZSkgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygpICU+JSBhcy5tYXRyaXgoKQpjYyA8LSBjb3IuZXh0KGMpICU+JSAjZHBseXI6OnJlbmFtZSgic3ltcHQiPXJvd25hbWUpICU+JSAKICBjb2x1bW5fdG9fcm93bmFtZXMoKSAlPiUgYXMubWF0cml4KCkKCnJlYWRyOjp3cml0ZV9yZHMoYWEsImRhdGEvY29yX2FsbC5yZHMiKQpyZWFkcjo6d3JpdGVfcmRzKGJiLCJkYXRhL2Nvcl9hc3ltcC5yZHMiKQpyZWFkcjo6d3JpdGVfcmRzKGNjLCJkYXRhL2Nvcl9zeW1wdC5yZHMiKQpgYGAKCmBgYHtyfQphYQpiYgpjYwoja25pdHI6OmthYmxlKGNjLCJsYXRleCIpCmBgYAoKYGBge3J9CmF4IDwtIHQoYXMubWF0cml4KGMoIiIsIiIsIiIsIiIsIiIpKSkKcm93bmFtZXMoYXgpIDwtICJBbGwgaW5kaXZpZHVhbHMiCmNvbG5hbWVzKGF4KSA8LSBjKCJJZ0ciLCJJZ0cxIiwiSWdHMiIsIklnRzMiLCJJZ0c0IikKYnggPC0gdChhcy5tYXRyaXgoYygiIiwiIiwiIiwiIiwiIikpKQpyb3duYW1lcyhieCkgPC0gIkFzeW1wdG9tYXRpY3MiCmNvbG5hbWVzKGJ4KSA8LSBjKCJJZ0ciLCJJZ0cxIiwiSWdHMiIsIklnRzMiLCJJZ0c0IikKY3ggPC0gdChhcy5tYXRyaXgoYygiIiwiIiwiIiwiIiwiIikpKQpyb3duYW1lcyhjeCkgPC0gIlN5bXB0b21hdGljcyIKY29sbmFtZXMoY3gpIDwtIGMoIklnRyIsIklnRzEiLCJJZ0cyIiwiSWdHMyIsIklnRzQiKQpkZCA8LSByYmluZChheCxhYSxieCxiYixjeCxjYylbLWMoNiwxMiwxOCksLTFdCnJlYWRyOjp3cml0ZV9yZHMoZGQsImRhdGEvY29yX2Z1bGwucmRzIikKYGBgCgpgYGB7cixtZXNzYWdlPUZBTFNFLGZpZy5oZWlnaHQ9NSxmaWcud2lkdGg9Nn0KI21jbyAlPiUgCiMgIGRwbHlyOjpzZWxlY3QocGhlbm8saWdnLEFiLnVuaXRzLHBhcikgJT4lIAojICBHR2FsbHk6OmdncGFpcnMobWFwcGluZyA9IGFlcyhjb2xvciA9IHBoZW5vKSkKCnVuaW9uKHUsdikgJT4lIAogIGRwbHlyOjpyZW5hbWUoIlN0YXR1cyI9cGhlbm8pICU+JSAKICBHR2FsbHk6Omdnc2NhdG1hdChjb2xvciA9ICJTdGF0dXMiLGNvck1ldGhvZCA9ICJzcGVhcm1hbiIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArCiAgbGFicyh0aXRsZT0iQ29ycmVsYXRpb24gYmV0d2VlbiBJZ0cgc3VidHlwZXMgcGVyIHBoZW5vdHlwZSIpIyArc2NhbGVfZmlsbF9ncmV5KHN0YXJ0ID0gMCwgZW5kID0gLjkpCgojIGNvcnJlbGFjacOzbiBnZW5lcmFsIHkgZXN0cmF0aWZpY2FkYQojdW5pb24odSx2KSAlPiUgCiMgIEdHYWxseTo6Z2dwYWlycyhtYXBwaW5nID0gYWVzKGNvbG9yID0gcGhlbm8pKQpgYGAKCmBgYHtyLGV2YWw9RkFMU0UsZWNobz1GQUxTRX0KbGlicmFyeShkZXNjdGFibGUpCmxpYnJhcnkoRFQpCmxpYnJhcnkocGFuZGVyKQptdGNhcnMgJT4lCiAgI2RwbHlyOjptdXRhdGUoYW0gPSBmYWN0b3IoYW0sIGxhYmVscyA9IGMoIkF1dG9tYXRpYyIsICJNYW51YWwiKSkpICU+JQogIGdyb3VwX2J5KGFtKSAlPiUKICBkZXNjdGFibGUodGVzdHMgPSBsaXN0KC5kZWZhdWx0ID0gfndpbGNveC50ZXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgbXBnICAgICAgPSB+dC50ZXN0KSkgJT4lCiAgcGFuZGVyCmBgYAoKIyMjIHBhcmFzaXRlbWlhCgpgYGB7cixmaWcuaGVpZ2h0PTIsZmlnLndpZHRoPTR9Cm1jbyAlPiUgCiAgZ2dwbG90KGFlcyhBYi51bml0cyxmaWxsPXBoZW5vKSkgKwogIGdlb21fZGVuc2l0eShwb3NpdGlvbiA9ICJpZGVudGl0eSIsYWxwaGE9MC42KSArCiAgI2dlb21fcnVnKCkgKyAKICBzY2FsZV94X2xvZzEwKCkKYGBgCgpgYGB7cixmaWcuaGVpZ2h0PTIsZmlnLndpZHRoPTR9Cm1jbyAlPiUgI3N1bW1hcnkobWNvJHBhcikKICBnZ3Bsb3QoYWVzKHBhcixmaWxsPXBoZW5vKSkgKwogIGdlb21fZGVuc2l0eShwb3NpdGlvbiA9ICJpZGVudGl0eSIsYWxwaGE9MC42KSArCiAgI2dlb21fcnVnKCkgKyAKICBzY2FsZV94X2xvZzEwKCkKYGBgCgpgYGB7cixmaWcuaGVpZ2h0PTMsZmlnLndpZHRoPTEwfQptY28gJT4lIAogIGdncGxvdChhZXMoQWIudW5pdHMscGFyLGZpbGw9cGhlbm8pKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyPXBoZW5vKSkgKwogIHNjYWxlX3hfbG9nMTAoKSArIAogIHNjYWxlX3lfbG9nMTAoKSArCiAgZmFjZXRfZ3JpZChwaGVub35pZ2csc2NhbGVzID0gImZyZWUiKSArCiAgZ2VvbV9zbW9vdGgoYWVzKGNvbG91cj1waGVubyksbWV0aG9kID0gbG0pCmBgYAoKYGBge3IsZmlnLmhlaWdodD00LGZpZy53aWR0aD02LGV2YWw9RkFMU0V9CnUgPC0gbWNvICU+JSBmaWx0ZXIocGhlbm89PSJhc3ltcHRvbWF0aWMiKSAlPiUgCiAgZHBseXI6OnNlbGVjdChJRCxpZ2csQWIudW5pdHMscGFyKSAlPiUgCiAgI211dGF0ZShBYi51bml0cz1sb2cxMChBYi51bml0cykpICU+JSAKICBzcHJlYWQoaWdnLEFiLnVuaXRzKSAlPiUgCiAgZHBseXI6OnNlbGVjdCgtSUQpCgp2IDwtIG1jbyAlPiUgZmlsdGVyKHBoZW5vPT0ic3ltcHRvbWF0aWMiKSAlPiUgCiAgZHBseXI6OnNlbGVjdChJRCxpZ2csQWIudW5pdHMscGFyKSAlPiUgCiAgI211dGF0ZShBYi51bml0cz1sb2cxMChBYi51bml0cykpICU+JSAKICBzcHJlYWQoaWdnLEFiLnVuaXRzKSAlPiUgCiAgZHBseXI6OnNlbGVjdCgtSUQpIAoKI3VuaW9uKHUsdikgJT4lIAojICBQZXJmb3JtYW5jZUFuYWx5dGljczo6Y2hhcnQuQ29ycmVsYXRpb24oaGlzdG9ncmFtID0gRkFMU0UsbWV0aG9kID0gInNwZWFybWFuIikKYGBgCgpgYGB7cixmaWcud2lkdGg9MTAsZmlnLmhlaWdodD0zLGV2YWw9RkFMU0V9Cm1jbyAlPiUgCiAgZ2dwbG90KGFlcyhBYi51bml0cyxwYXIpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyPXBoZW5vKSkgKwogIHNjYWxlX3hfbG9nMTAoKSArCiAgc2NhbGVfeV9sb2cxMCgpICsKICBmYWNldF9ncmlkKHBoZW5vfmlnZwogICAgICAgICAgICAgIyxzY2FsZXMgPSAiZnJlZSIKICAgICAgICAgICAgICkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9IGxtKQpgYGAKCmBgYHtyLG1lc3NhZ2U9RkFMU0UsZmlnLndpZHRoPTEwLGZpZy5oZWlnaHQ9My42fQpmIDwtIG1jbyAlPiUgbXV0YXRlKGlnZz1hcy5mYWN0b3IoaWdnKSkgJT4lIC4kaWdnCmcgPC0gbWNvICU+JSBtdXRhdGUocGhlbm89YXMuZmFjdG9yKHBoZW5vKSkgJT4lIC4kcGhlbm8KCiNtY28gPC0gbWNvICU+JSAKIyAgI2RwbHlyOjpzZWxlY3QoQWIudW5pdHMscGFyKSAlPiUgCiMgIG11dGF0ZShBYi51bml0cz1sb2cxMChBYi51bml0cykscGFyPWxvZzEwKHBhcikpICU+JSAKIyAgZmlsdGVyKHBhciE9LUluZikgIyU+JSAKCnN0dCA8LSBkYXRhX2ZyYW1lKGVzdGltYXRlPWFzLmRvdWJsZSgpLAogICAgICAgICAgICAgICAgICAjI2VzdGltYXRlMT1hcy5kb3VibGUoKSwKICAgICAgICAgICAgICAgICAgIyNlc3RpbWF0ZTI9YXMuZG91YmxlKCksCiAgICAgICAgICAgICAgICAgIHN0YXRpc3RpYz1hcy5kb3VibGUoKSwKICAgICAgICAgICAgICAgICAgcC52YWx1ZT1hcy5kb3VibGUoKSwKICAgICAgICAgICAgICAgICAgcGFyYW1ldGVyPWFzLmRvdWJsZSgpLCMKICAgICAgICAgICAgICAgICAgY29uZi5sb3c9YXMuZG91YmxlKCksIwogICAgICAgICAgICAgICAgICBjb25mLmhpZ2g9YXMuZG91YmxlKCksIwogICAgICAgICAgICAgICAgICBtZXRob2Q9YXMuZmFjdG9yKE5VTEwpLAogICAgICAgICAgICAgICAgICBhbHRlcm5hdGl2ZT1hcy5mYWN0b3IoTlVMTCksCiAgICAgICAgICAgICAgICAgIGlnZz1hcy5jaGFyYWN0ZXIoKSwKICAgICAgICAgICAgICAgICAgcGhlbm89YXMuY2hhcmFjdGVyKCksCiAgICAgICAgICAgICAgICAgIHNpZ25mPWFzLmNoYXJhY3RlcigpLAogICAgICAgICAgICAgICAgICByaG89YXMuY2hhcmFjdGVyKCksCiAgICAgICAgICAgICAgICAgIGxhYj1hcy5jaGFyYWN0ZXIoKSkKCmZvciAobCBpbiAxOmxlbmd0aChsZXZlbHMoZikpKSB7CiAgCiAgZm9yIChrIGluIDE6bGVuZ3RoKGxldmVscyhnKSkpIHsKICAgIAojIyBQcmltZXJvLApqIDwtIG1jbyAlPiUgZmlsdGVyKHBhciE9MCkgJT4lICBmaWx0ZXIoaWdnPT1sZXZlbHMoZilbbF0gJiBwaGVubz09bGV2ZWxzKGcpW2tdKSAlPiUgI2wgI2sKICAjdC50ZXN0KEFiLnVuaXRzX2xvZyB+IHBoZW5vLCBkYXRhID0gLiwgdmFyLmVxdWFsPSBpJHAudmFsdWU+MC4wNSkgJT4lCiAgI3dpbGNveC50ZXN0KEFiLnVuaXRzX2xvZyB+IHBoZW5vLCBkYXRhID0gLikgJT4lIywgCiAgICAgICAgICAgICAgI2NvbmYuaW50PVRSVUUpICU+JSAKICBjb3IudGVzdCh+IGxvZzEwKEFiLnVuaXRzKSArIGxvZzEwKHBhciksIAogICAgICAgICAgIGRhdGEgPSAuLCBtZXRob2QgPSAicGVhcnNvbiIpICU+JSAKICBicm9vbTo6dGlkeSgpICU+JSAgIyU+JSBmb3JtYXQoZGlnaXRzPTIpCiAgI2RwbHlyOjpzZWxlY3QoLXN0YXJ0c193aXRoKCJlc3RpbWF0ZSIpKSAlPiUgCiAgbXV0YXRlKGlnZz1sZXZlbHMoZilbbF0sI2wKICAgICAgICAgcGhlbm89bGV2ZWxzKGcpW2tdLCNrCiAgICAgICAgIHNpZ25mPWlmX2Vsc2UocC52YWx1ZTwwLjAwMSwib29vIiwKICAgICAgICAgICAgICAgICAgICAgICBpZl9lbHNlKHAudmFsdWU8MC4wMSwib28iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZfZWxzZShwLnZhbHVlPDAuMDUsIm8iLCJucyIjIiIjCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpKSwKICAgICAgICAgcmhvPSBlc3RpbWF0ZSAlPiUgZm9ybWF0KGRpZ2l0cz0yKSwKICAgICAgICAgbGFiPSBwYXN0ZTAoIyJ0PSIsI3Nob3VsZCBiZSBkb25lIC0+IG1peCB2YXJpYW5jZSBlcXVhbGl0eSB0ZXN0CiAgICAgICAgICAgICAgICAgICAgICMiVz0iLCNub24tcGFyYW1ldHJpYyB1c2VkIGluIGxpdGVyYXR1cmUKICAgICAgICAgICAgICAgICAgICAgIyJTPSIsZiRzdGF0aXN0aWMsIiwgcmhvPSIKICAgICAgICAgICAgICAgICAgICAgInJobz0iLGVzdGltYXRlICU+JSBmb3JtYXQoZGlnaXRzPTIpLAogICAgICAgICAgICAgICAgICAgICAiXG5QIixpZmVsc2UocC52YWx1ZTwwLjAwMSwiPDAuMDAxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlMCgiPSIscC52YWx1ZSAlPiUgZm9ybWF0KGRpZ2l0cz0yKSkpCiAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgKQoKI2kgPC0gbWNvICU+JSBmaWx0ZXIoaWdnPT1sZXZlbHMoZilbbF0gJiBwaGVubz09bGV2ZWxzKGcpW2tdKSAlPiUgI2wgI2sKIyAgI3QudGVzdChBYi51bml0c19sb2cgfiBwaGVubywgZGF0YSA9IC4sIHZhci5lcXVhbD0gaSRwLnZhbHVlPjAuMDUpICU+JQojICAjd2lsY294LnRlc3QoQWIudW5pdHNfbG9nIH4gcGhlbm8sIGRhdGEgPSAuKSAlPiUjLCAKIyAgICAgICAgICAgICAgI2NvbmYuaW50PVRSVUUpICU+JSAKIyAgY29yLnRlc3QofiBBYi51bml0cyArIHBhciwgCiMgICAgICAgICAgIGRhdGEgPSAuLCBtZXRob2QgPSAic3BlYXJtYW4iKSAlPiUgCiMgIGJyb29tOjp0aWR5KCkgJT4lICAjJT4lIGZvcm1hdChkaWdpdHM9MikKIyAgI2RwbHlyOjpzZWxlY3QoLXN0YXJ0c193aXRoKCJlc3RpbWF0ZSIpKSAlPiUgCiMgIG11dGF0ZShpZ2c9bGV2ZWxzKGYpW2xdLCNsCiMgICAgICAgICBwaGVubz1sZXZlbHMoZylba10sI2sKIyAgICAgICAgIHNpZ25mPWlmX2Vsc2UocC52YWx1ZTwwLjAwMSwiKCoqKikiLAojICAgICAgICAgICAgICAgICAgICAgICBpZl9lbHNlKHAudmFsdWU8MC4wMSwiKCoqKSIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZfZWxzZShwLnZhbHVlPDAuMDUsIigqKSIsIihucykiKSkpLAojICAgICAgICAgcmhvPSBlc3RpbWF0ZSAlPiUgZm9ybWF0KGRpZ2l0cz0yKSwKIyAgICAgICAgIGxhYj0gcGFzdGUwKCMidD0iLCNzaG91bGQgYmUgZG9uZSAtPiBtaXggdmFyaWFuY2UgZXF1YWxpdHkgdGVzdAojICAgICAgICAgICAgICAgICAgICAgIyJXPSIsI25vbi1wYXJhbWV0cmljIHVzZWQgaW4gbGl0ZXJhdHVyZQojICAgICAgICAgICAgICAgICAgICAgIyJTPSIsZiRzdGF0aXN0aWMsIiwgcmhvPSIKIyAgICAgICAgICAgICAgICAgICAgICJyaG89Iixlc3RpbWF0ZSAlPiUgZm9ybWF0KGRpZ2l0cz0yKSMsCiMgICAgICAgICAgICAgICAgICAgICAjIlxuUCIsaWZlbHNlKHAudmFsdWU8MC4wMDEsIjwwLjAwMSIsCiMgICAgICAgICAgICAgICAgICAgICAgIyAgICAgICAgICAgIHBhc3RlMCgiPSIscC52YWx1ZSAlPiUgZm9ybWF0KGRpZ2l0cz0yKSkpCiMgICAgICAgICAgICAgICAgICAgICApCiMgICAgICAgICApCgpzdHQgPC0gc3R0ICU+JSB1bmlvbihqKSAjJT4lIHVuaW9uKGkpCiAgICAKICB9Cgp9CgpzdHR0IDwtIHN0dCAlPiUgYXJyYW5nZShpZ2cscGhlbm8pICU+JSBkcGx5cjo6c2VsZWN0KGlnZyxwaGVubyxldmVyeXRoaW5nKCkpICU+JSAKICBtdXRhdGUoeD1pZl9lbHNlKGlnZz09ImlnZzEifGlnZz09ImlnZzMifGlnZz09ImlnZzQiLDEwLAogICAgICAgICAgICAgICAgICAgaWZfZWxzZShpZ2c9PSJpZ2cyIiwuNywuMSkpLAogICAgICAgICB5PTYwMDAwKQoKIyBwbG90CnNwZWNpZV9uYW1lIDwtIGMoImFzeW1wdG9tYXRpYyI9IkFzeW1wdG9tYXRpYyIsInN5bXB0b21hdGljIj0iU3ltcHRvbWF0aWMiLAogICAgICAgICAgICAgICAgICJpZ2ciPSJJZ0ciLCJpZ2cxIj0iSWdHMSIsImlnZzIiPSJJZ0cyIiwiaWdnMyI9IklnRzMiLCJpZ2c0Ij0iSWdHNCIKICAgICAgICAgICAgICAgICApCm1jbyAlPiUgCiAgZmlsdGVyKHBhciE9MCkgJT4lIAogIGdncGxvdChhZXMoQWIudW5pdHMscGFyKSkgKwogIGdlb21fcG9pbnQoI2Flcyhjb2xvdXI9cGhlbm8pCiAgICAgICAgICAgICApICsKICBzY2FsZV94X2xvZzEwKCkgKwogIHNjYWxlX3lfbG9nMTAobGltaXRzPWMoMTAwLDY1MDAwKQogICAgICAgICAgICAgICAgKSArCiAgZmFjZXRfZ3JpZChwaGVub35pZ2csbGFiZWxsZXIgPSBhc19sYWJlbGxlcihzcGVjaWVfbmFtZSkKICAgICAgICAgICAgICxzY2FsZXMgPSAiZnJlZV94IgogICAgICAgICAgICAgKSArCiAgI2dlb21fc21vb3RoKG1ldGhvZCA9IGxtLHNlPUYsY29sPSJncmV5NTAiLGx3ZD0uNSkgKwogICNnZW9tX3Ntb290aChtZXRob2QgPSBsb2VzcyxzZT1GLGNvbD0iZ3JleTUwIixsd2Q9LjUpICsKICAKICBnZW9tX3RleHQoYWVzKHgseSxsYWJlbD1wYXN0ZTAoInIiLCI9PSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJobywiXiIsc2lnbmYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSksZGF0YSA9IHN0dHQsIHBhcnNlID0gVCwKICAgICAgICAgICAgdmp1c3Q9MSxoanVzdD0wLjA1LHNpemU9My41KSArCiAgCiAgI2xhYnMoI3RpdGxlPSJDb3JyZWxhdGlvbiBiZXR3ZWVuIEFVIGFuZCBwYXJhc2l0ZW1pYSBwZXIgSWdHIHN1YnR5cGUgYW5kIHBoZW5vdHlwZSIsCiAgICMgICAgY2FwdGlvbj0ib286IFAgPCAwLjAxOyBvOiBQIDwgMC4wNTsgbnM6IG5vbi1zaWduaWZpY2FudCIKICAgICMgICApICsKICB4bGFiKCJBbnRpYm9keSB1bml0cyAobG9nIHNjYWxlKSIpICsgCiAgeWxhYihleHByZXNzaW9uKHBhc3RlKCJQYXJhc2l0ZS8iLG11LCJMIiwiIChsb2cgc2NhbGUpIikpKSAjKyAjeWxhYigiUGFyYXNpdGUvdUwiKSArCiAgI2Nvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLDIwMDAwKSkKICAjc2NhbGVfY29sb3JfZ3JleSgjc3RhcnQgPSAwLCBlbmQgPSAuOSwKICAgIyAgICAgICAgICAgICAgIG5hbWU9IkNhcnJpZXIiLGxhYmVscz1jKCJBc3ltcHRvbWF0aWMiLCJTeW1wdG9tYXRpYyIjLCJJbmRldGVybWluYXRlIgogICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpCmBgYApgYGB7cn0KZCA8LSBkYXRhLmZyYW1lKHg9MTozLHk9MTozKQpxcGxvdCh4LCB5LCBkYXRhPWQpICsgZ2VvbV90ZXh0KGFlcygyLCAyLjUsCiAgICAgICAgICAgICAgbGFiZWw9InJob35hbmR+c29tZX5vdGhlcn50ZXh0IiksIHBhcnNlPVRSVUUpCmBgYAoKYGBge3IsbWVzc2FnZT1GQUxTRSxmaWcud2lkdGg9MTAsZmlnLmhlaWdodD0yLjJ9CmYgPC0gbWNvICU+JSBtdXRhdGUoaWdnPWFzLmZhY3RvcihpZ2cpKSAlPiUgLiRpZ2cKCiNtY28gPC0gbWNvICU+JSAKIyAgI2RwbHlyOjpzZWxlY3QoQWIudW5pdHMscGFyKSAlPiUgCiMgIG11dGF0ZShBYi51bml0cz1sb2cxMChBYi51bml0cykscGFyPWxvZzEwKHBhcikpICU+JSAKIyAgZmlsdGVyKHBhciE9LUluZikgIyU+JSAKCnN0dCA8LSBkYXRhX2ZyYW1lKGVzdGltYXRlPWFzLmRvdWJsZSgpLAogICAgICAgICAgICAgICAgICAjI2VzdGltYXRlMT1hcy5kb3VibGUoKSwKICAgICAgICAgICAgICAgICAgIyNlc3RpbWF0ZTI9YXMuZG91YmxlKCksCiAgICAgICAgICAgICAgICAgIHN0YXRpc3RpYz1hcy5kb3VibGUoKSwKICAgICAgICAgICAgICAgICAgcC52YWx1ZT1hcy5kb3VibGUoKSwKICAgICAgICAgICAgICAgICAgI3BhcmFtZXRlcj1hcy5kb3VibGUoKSwjCiAgICAgICAgICAgICAgICAgICNjb25mLmxvdz1hcy5kb3VibGUoKSwjCiAgICAgICAgICAgICAgICAgICNjb25mLmhpZ2g9YXMuZG91YmxlKCksIwogICAgICAgICAgICAgICAgICBtZXRob2Q9YXMuZmFjdG9yKE5VTEwpLAogICAgICAgICAgICAgICAgICBhbHRlcm5hdGl2ZT1hcy5mYWN0b3IoTlVMTCksCiAgICAgICAgICAgICAgICAgIGlnZz1hcy5jaGFyYWN0ZXIoKSwKICAgICAgICAgICAgICAgICAgbGFiPWFzLmNoYXJhY3RlcigpKQoKZm9yIChsIGluIDE6bGVuZ3RoKGxldmVscyhmKSkpIHsKICAKIyMgUHJpbWVybywKaiA8LSBtY28gJT4lIGZpbHRlcihpZ2c9PWxldmVscyhmKVtsXSkgJT4lICNsCiAgI3QudGVzdChBYi51bml0c19sb2cgfiBwaGVubywgZGF0YSA9IC4sIHZhci5lcXVhbD0gaSRwLnZhbHVlPjAuMDUpICU+JQogICN3aWxjb3gudGVzdChBYi51bml0c19sb2cgfiBwaGVubywgZGF0YSA9IC4pICU+JSMsIAogICAgICAgICAgICAgICNjb25mLmludD1UUlVFKSAlPiUgCiAgY29yLnRlc3QofiBBYi51bml0cyArIHBhciwgCiAgICAgICAgICAgZGF0YSA9IC4sIG1ldGhvZCA9ICJzcGVhcm1hbiIpICU+JSAKICBicm9vbTo6dGlkeSgpICU+JSAgIyU+JSBmb3JtYXQoZGlnaXRzPTIpCiAgI2RwbHlyOjpzZWxlY3QoLXN0YXJ0c193aXRoKCJlc3RpbWF0ZSIpKSAlPiUgCiAgbXV0YXRlKGlnZz1sZXZlbHMoZilbbF0sI2wKICAgICAgICAgbGFiPSBwYXN0ZTAoIyJ0PSIsI3Nob3VsZCBiZSBkb25lIC0+IG1peCB2YXJpYW5jZSBlcXVhbGl0eSB0ZXN0CiAgICAgICAgICAgICAgICAgICAgICMiVz0iLCNub24tcGFyYW1ldHJpYyB1c2VkIGluIGxpdGVyYXR1cmUKICAgICAgICAgICAgICAgICAgICAgIyJTPSIsZiRzdGF0aXN0aWMsIiwgcmhvPSIKICAgICAgICAgICAgICAgICAgICAgInJobz0iLGVzdGltYXRlICU+JSBmb3JtYXQoZGlnaXRzPTIpLAogICAgICAgICAgICAgICAgICAgICAiXG5QIixpZmVsc2UocC52YWx1ZTwwLjAwMSwiPDAuMDAxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlMCgiPSIscC52YWx1ZSAlPiUgZm9ybWF0KGRpZ2l0cz0yKSkpCiAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgKQoKc3R0IDwtIHN0dCAlPiUgdW5pb24oaikKCn0KCnN0dCA8LSBzdHQgJT4lIGFycmFuZ2UoaWdnKSAlPiUgZHBseXI6OnNlbGVjdChpZ2csZXZlcnl0aGluZygpKSAlPiUgCiAgbXV0YXRlKHg9LjEsCiAgICAgICAgIHk9MjAwKQoKIyBwbG90Cm1jbyAlPiUgI2ZpbHRlcihpZ2c9PWxldmVscyhmKVsxXSkgJT4lIAogIGdncGxvdChhZXMoQWIudW5pdHMscGFyKSkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfeF9sb2cxMCgpICsKICBzY2FsZV95X2xvZzEwKCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9IGxtLHNlPUYsY29sPSJncmV5NTAiLGx3ZD0uNSkgKwogICNnZW9tX3Ntb290aChtZXRob2QgPSBsb2VzcyxzZT1GLGNvbD0iZ3JleTUwIixsd2Q9LjUpICsKICBnZW9tX3RleHQoYWVzKHgseSxsYWJlbD1sYWIpLGRhdGEgPSBzdHQsCiAgICAgICAgICAgIHZqdXN0PS41LGhqdXN0PTAuMDUsc2l6ZT0zLjUpICsKICBmYWNldF9ncmlkKH5pZ2cKICAgICAgICAgICAgICMsc2NhbGVzID0gImZyZWUiCiAgICAgICAgICAgICApICsKICAjZmFjZXRfd3JhcCh+aWdnLG5jb2wgPSA1KQogIGxhYnModGl0bGU9IkNvcnJlbGF0aW9uIGJldHdlZW4gQVUgYW5kIHBhcmFzaXRlbWlhIHBlciBJZ0cgc3VidHlwZSIpCmBgYAoKYGBge3IsZXZhbD1GQUxTRSxpbmNsdWRlPUZBTFNFfQojIENIVU5LOiB0byBjb21wYXJlIGBwZWFyc29uIGNvci50ZXN0YCA9IGBsbWAgIT0gYHNwZWFybWFuIGNvci50ZXN0YAoKI2ZvciAobCBpbiAxOmxlbmd0aChsZXZlbHMoZikpKSB7CiMjIHZpYSBsbQpsPTEKbWNvICU+JSBmaWx0ZXIoaWdnPT1sZXZlbHMoZilbbF0gJiBwaGVubz09InN5bXB0b21hdGljIikgJT4lICNsPTIKICAjdC50ZXN0KEFiLnVuaXRzX2xvZyB+IHBoZW5vLCBkYXRhID0gLiwgdmFyLmVxdWFsPSBpJHAudmFsdWU+MC4wNSkgJT4lCiAgI3dpbGNveC50ZXN0KEFiLnVuaXRzX2xvZyB+IHBoZW5vLCBkYXRhID0gLikgJT4lIywgCiAgICAgICAgICAgICAgI2NvbmYuaW50PVRSVUUpICU+JSAKICAjY29yLnRlc3QofiBBYi51bml0cyArIHBhciwgbWV0aG9kID0gInNwZWFybWFuIiwKICBsbShwYXIgfiBBYi51bml0cywgCiAgICAgICAgICAgZGF0YSA9IC4jLCBtZXRob2QgPSAic3BlYXJtYW4iCiAgICAgKSAlPiUgCiAgYnJvb206OnRpZHkoKQoKI30KYGBgCgojIyMgYWdlCgpgYGB7cn0KYWdlIDwtIG1jbyAlPiUgCiAgZHBseXI6OnNlbGVjdChJRCwgY29kZSwgcGhlbm8sIGlnZywgQWIudW5pdHMpICU+JSAKICBmdWxsX2pvaW4obWN2LGJ5PWMoIklEIiwicGhlbm8iKSkKYGBgCgpgYGB7cixmaWcuaGVpZ2h0PTIsZmlnLndpZHRoPTEwfQphZ2UgJT4lICNzdW1tYXJ5KGFnZSRlZGFkKQogIGdncGxvdChhZXMoQWIudW5pdHMsZmlsbD1waGVubykpICsKICBnZW9tX2RlbnNpdHkocG9zaXRpb24gPSAiaWRlbnRpdHkiLGFscGhhPTAuNykgKwogIGZhY2V0X3dyYXAofmlnZyxzY2FsZXMgPSAiZnJlZSIsbmNvbCA9IDUpICMrc2NhbGVfeF9sb2cxMCgpCmBgYAoKYGBge3IsZmlnLmhlaWdodD0yLGZpZy53aWR0aD00fQphZ2UgJT4lICNzdW1tYXJ5KGFnZSRlZGFkKQogIGdncGxvdChhZXMoZWRhZCxmaWxsPXBoZW5vKSkgKwogIGdlb21fZGVuc2l0eShwb3NpdGlvbiA9ICJpZGVudGl0eSIsYWxwaGE9MC43KQpgYGAKCgpgYGB7cixtZXNzYWdlPUZBTFNFLGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTMuNn0KZiA8LSBhZ2UgJT4lIG11dGF0ZShpZ2c9YXMuZmFjdG9yKGlnZykpICU+JSAuJGlnZwpnIDwtIGFnZSAlPiUgbXV0YXRlKHBoZW5vPWFzLmZhY3RvcihwaGVubykpICU+JSAuJHBoZW5vCgojbWNvIDwtIG1jbyAlPiUgCiMgICNkcGx5cjo6c2VsZWN0KEFiLnVuaXRzLHBhcikgJT4lIAojICBtdXRhdGUoQWIudW5pdHM9bG9nMTAoQWIudW5pdHMpLHBhcj1sb2cxMChwYXIpKSAlPiUgCiMgIGZpbHRlcihwYXIhPS1JbmYpICMlPiUgCgpzdHQgPC0gZGF0YV9mcmFtZShlc3RpbWF0ZT1hcy5kb3VibGUoKSwKICAgICAgICAgICAgICAgICAgIyNlc3RpbWF0ZTE9YXMuZG91YmxlKCksCiAgICAgICAgICAgICAgICAgICMjZXN0aW1hdGUyPWFzLmRvdWJsZSgpLAogICAgICAgICAgICAgICAgICBzdGF0aXN0aWM9YXMuZG91YmxlKCksCiAgICAgICAgICAgICAgICAgIHAudmFsdWU9YXMuZG91YmxlKCksCiAgICAgICAgICAgICAgICAgICNwYXJhbWV0ZXI9YXMuZG91YmxlKCksIwogICAgICAgICAgICAgICAgICAjY29uZi5sb3c9YXMuZG91YmxlKCksIwogICAgICAgICAgICAgICAgICAjY29uZi5oaWdoPWFzLmRvdWJsZSgpLCMKICAgICAgICAgICAgICAgICAgbWV0aG9kPWFzLmZhY3RvcihOVUxMKSwKICAgICAgICAgICAgICAgICAgYWx0ZXJuYXRpdmU9YXMuZmFjdG9yKE5VTEwpLAogICAgICAgICAgICAgICAgICBpZ2c9YXMuY2hhcmFjdGVyKCksCiAgICAgICAgICAgICAgICAgIHBoZW5vPWFzLmNoYXJhY3RlcigpLAogICAgICAgICAgICAgICAgICBzaWduZj1hcy5jaGFyYWN0ZXIoKSwKICAgICAgICAgICAgICAgICAgcmhvPWFzLmNoYXJhY3RlcigpLAogICAgICAgICAgICAgICAgICBsYWI9YXMuY2hhcmFjdGVyKCkpCgpmb3IgKGwgaW4gMTpsZW5ndGgobGV2ZWxzKGYpKSkgewogIAogIGZvciAoayBpbiAxOmxlbmd0aChsZXZlbHMoZykpKSB7CiAgICAKIyMgUHJpbWVybywKaiA8LSBhZ2UgJT4lIGZpbHRlcihpZ2c9PWxldmVscyhmKVtsXSAmIHBoZW5vPT1sZXZlbHMoZylba10pICU+JSAjbCAjawogICN0LnRlc3QoQWIudW5pdHNfbG9nIH4gcGhlbm8sIGRhdGEgPSAuLCB2YXIuZXF1YWw9IGkkcC52YWx1ZT4wLjA1KSAlPiUKICAjd2lsY294LnRlc3QoQWIudW5pdHNfbG9nIH4gcGhlbm8sIGRhdGEgPSAuKSAlPiUjLCAKICAgICAgICAgICAgICAjY29uZi5pbnQ9VFJVRSkgJT4lIAogIGNvci50ZXN0KH4gQWIudW5pdHMgKyBlZGFkLCAKICAgICAgICAgICBkYXRhID0gLiwgbWV0aG9kID0gInNwZWFybWFuIikgJT4lIAogIGJyb29tOjp0aWR5KCkgJT4lICAjJT4lIGZvcm1hdChkaWdpdHM9MikKICAjZHBseXI6OnNlbGVjdCgtc3RhcnRzX3dpdGgoImVzdGltYXRlIikpICU+JSAKICBtdXRhdGUoaWdnPWxldmVscyhmKVtsXSwjbAogICAgICAgICBwaGVubz1sZXZlbHMoZylba10sI2sKICAgICAgICAgc2lnbmY9aWZfZWxzZShwLnZhbHVlPDAuMDAxLCJvb28iLAogICAgICAgICAgICAgICAgICAgICAgIGlmX2Vsc2UocC52YWx1ZTwwLjAxLCJvbyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZl9lbHNlKHAudmFsdWU8MC4wNSwibyIsIm5zIiMiIiMKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkpLAogICAgICAgICByaG89IGVzdGltYXRlICU+JSBmb3JtYXQoZGlnaXRzPTIpLAogICAgICAgICBsYWI9IHBhc3RlMCgjInQ9Iiwjc2hvdWxkIGJlIGRvbmUgLT4gbWl4IHZhcmlhbmNlIGVxdWFsaXR5IHRlc3QKICAgICAgICAgICAgICAgICAgICAgIyJXPSIsI25vbi1wYXJhbWV0cmljIHVzZWQgaW4gbGl0ZXJhdHVyZQogICAgICAgICAgICAgICAgICAgICAjIlM9IixmJHN0YXRpc3RpYywiLCByaG89IgogICAgICAgICAgICAgICAgICAgICAicmhvPSIsZXN0aW1hdGUgJT4lIGZvcm1hdChkaWdpdHM9MiksCiAgICAgICAgICAgICAgICAgICAgICJcblAiLGlmZWxzZShwLnZhbHVlPDAuMDAxLCI8MC4wMDEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKCI9IixwLnZhbHVlICU+JSBmb3JtYXQoZGlnaXRzPTIpKSkKICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICApCgojaSA8LSBhZ2UgJT4lIGZpbHRlcihpZ2c9PWxldmVscyhmKVtsXSAmIHBoZW5vPT1sZXZlbHMoZylba10pICU+JSAjbCAjawojICAjdC50ZXN0KEFiLnVuaXRzX2xvZyB+IHBoZW5vLCBkYXRhID0gLiwgdmFyLmVxdWFsPSBpJHAudmFsdWU+MC4wNSkgJT4lCiMgICN3aWxjb3gudGVzdChBYi51bml0c19sb2cgfiBwaGVubywgZGF0YSA9IC4pICU+JSMsIAojICAgICAgICAgICAgICAjY29uZi5pbnQ9VFJVRSkgJT4lIAojICBjb3IudGVzdCh+IEFiLnVuaXRzICsgZWRhZCwgCiMgICAgICAgICAgIGRhdGEgPSAuLCBtZXRob2QgPSAic3BlYXJtYW4iKSAlPiUgCiMgIGJyb29tOjp0aWR5KCkgJT4lICAjJT4lIGZvcm1hdChkaWdpdHM9MikKIyAgI2RwbHlyOjpzZWxlY3QoLXN0YXJ0c193aXRoKCJlc3RpbWF0ZSIpKSAlPiUgCiMgIG11dGF0ZShpZ2c9bGV2ZWxzKGYpW2xdLCNsCiMgICAgICAgICBwaGVubz1sZXZlbHMoZylba10sI2sKIyAgICAgICAgIGxhYj0gcGFzdGUwKCMidD0iLCNzaG91bGQgYmUgZG9uZSAtPiBtaXggdmFyaWFuY2UgZXF1YWxpdHkgdGVzdAojICAgICAgICAgICAgICAgICAgICAgIyJXPSIsI25vbi1wYXJhbWV0cmljIHVzZWQgaW4gbGl0ZXJhdHVyZQojICAgICAgICAgICAgICAgICAgICAgIyJTPSIsZiRzdGF0aXN0aWMsIiwgcmhvPSIKIyAgICAgICAgICAgICAgICAgICAgICJyaG89Iixlc3RpbWF0ZSAlPiUgZm9ybWF0KGRpZ2l0cz0yKSwKIyAgICAgICAgICAgICAgICAgICAgICJcblAiLGlmZWxzZShwLnZhbHVlPDAuMDAxLCI8MC4wMDEiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlMCgiPSIscC52YWx1ZSAlPiUgZm9ybWF0KGRpZ2l0cz0yKSkpCiMgICAgICAgICAgICAgICAgICAgICApCiMgICAgICAgICApCgpzdHQgPC0gc3R0ICU+JSB1bmlvbihqKSAjJT4lIHVuaW9uKGkpCiAgICAKICB9Cgp9CgpzdHR1IDwtIHN0dCAlPiUgYXJyYW5nZShpZ2cscGhlbm8pICU+JSBkcGx5cjo6c2VsZWN0KGlnZyxwaGVubyxldmVyeXRoaW5nKCkpICU+JSAKICBtdXRhdGUoeD0uMSwKICAgICAgICAgeT03OCkKCiMgcGxvdApzcGVjaWVfbmFtZSA8LSBjKCJhc3ltcHRvbWF0aWMiPSJBc3ltcHRvbWF0aWMiLCJzeW1wdG9tYXRpYyI9IlN5bXB0b21hdGljIiwKICAgICAgICAgICAgICAgICAiaWdnIj0iSWdHIiwiaWdnMSI9IklnRzEiLCJpZ2cyIj0iSWdHMiIsImlnZzMiPSJJZ0czIiwiaWdnNCI9IklnRzQiCiAgICAgICAgICAgICAgICAgKQphZ2UgJT4lIAogIGdncGxvdChhZXMoQWIudW5pdHMsZWRhZCkpICsKICBnZW9tX3BvaW50KCNhZXMoY29sb3VyPXBoZW5vKQogICAgICAgICAgICAgKSArCiAgI3NjYWxlX3hfbG9nMTAoKSArCiAgI3NjYWxlX3lfbG9nMTAoKSArCiAgZmFjZXRfZ3JpZChwaGVub35pZ2csbGFiZWxsZXIgPSBhc19sYWJlbGxlcihzcGVjaWVfbmFtZSkKICAgICAgICAgICAgICxzY2FsZXMgPSAiZnJlZV94IgogICAgICAgICAgICAgKSArCiAgI2dlb21fc21vb3RoKG1ldGhvZCA9IGxtLHNlPUYsY29sPSJncmV5NTAiLGx3ZD0uNSkgKwogICNnZW9tX3Ntb290aChtZXRob2QgPSBsb2VzcyxzZT1GLGNvbD0iZ3JleTUwIixsd2Q9LjUpICsKICBnZW9tX3RleHQoYWVzKHgseSxsYWJlbD1wYXN0ZTAoInJobyIsIj09IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmhvLCJeIixzaWduZgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKSxkYXRhID0gc3R0dSwgcGFyc2UgPSBULAogICAgICAgICAgICB2anVzdD0uNSxoanVzdD0wLjA1LHNpemU9My41KSArCiAgI2xhYnModGl0bGU9IkNvcnJlbGF0aW9uIGJldHdlZW4gQVUgYW5kIHBhcmFzaXRlbWlhIHBlciBJZ0cgc3VidHlwZSBhbmQgcGhlbm90eXBlIikgKwogIHhsYWIoIkFudGlib2R5IHVuaXRzIikgKyB5bGFiKCJBZ2UgKHllYXJzKSIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCw4NSkpCiAgI3NjYWxlX2NvbG9yX2dyZXkoI3N0YXJ0ID0gMCwgZW5kID0gLjksCiAgICMgICAgICAgICAgICAgICBuYW1lPSJDYXJyaWVyIixsYWJlbHM9YygiQXN5bXB0b21hdGljIiwiU3ltcHRvbWF0aWMiIywiSW5kZXRlcm1pbmF0ZSIKICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKQpgYGAKCmBgYHtyLG1lc3NhZ2U9RkFMU0UsZmlnLndpZHRoPTEwLGZpZy5oZWlnaHQ9Mi4yfQpmIDwtIGFnZSAlPiUgbXV0YXRlKGlnZz1hcy5mYWN0b3IoaWdnKSkgJT4lIC4kaWdnCgojbWNvIDwtIG1jbyAlPiUgCiMgICNkcGx5cjo6c2VsZWN0KEFiLnVuaXRzLHBhcikgJT4lIAojICBtdXRhdGUoQWIudW5pdHM9bG9nMTAoQWIudW5pdHMpLHBhcj1sb2cxMChwYXIpKSAlPiUgCiMgIGZpbHRlcihwYXIhPS1JbmYpICMlPiUgCgpzdHQgPC0gZGF0YV9mcmFtZShlc3RpbWF0ZT1hcy5kb3VibGUoKSwKICAgICAgICAgICAgICAgICAgIyNlc3RpbWF0ZTE9YXMuZG91YmxlKCksCiAgICAgICAgICAgICAgICAgICMjZXN0aW1hdGUyPWFzLmRvdWJsZSgpLAogICAgICAgICAgICAgICAgICBzdGF0aXN0aWM9YXMuZG91YmxlKCksCiAgICAgICAgICAgICAgICAgIHAudmFsdWU9YXMuZG91YmxlKCksCiAgICAgICAgICAgICAgICAgICNwYXJhbWV0ZXI9YXMuZG91YmxlKCksIwogICAgICAgICAgICAgICAgICAjY29uZi5sb3c9YXMuZG91YmxlKCksIwogICAgICAgICAgICAgICAgICAjY29uZi5oaWdoPWFzLmRvdWJsZSgpLCMKICAgICAgICAgICAgICAgICAgbWV0aG9kPWFzLmZhY3RvcihOVUxMKSwKICAgICAgICAgICAgICAgICAgYWx0ZXJuYXRpdmU9YXMuZmFjdG9yKE5VTEwpLAogICAgICAgICAgICAgICAgICBpZ2c9YXMuY2hhcmFjdGVyKCksCiAgICAgICAgICAgICAgICAgIGxhYj1hcy5jaGFyYWN0ZXIoKSkKCmZvciAobCBpbiAxOmxlbmd0aChsZXZlbHMoZikpKSB7CiAgCiMjIFByaW1lcm8sCmogPC0gYWdlICU+JSBmaWx0ZXIoaWdnPT1sZXZlbHMoZilbbF0pICU+JSAjbAogICN0LnRlc3QoQWIudW5pdHNfbG9nIH4gcGhlbm8sIGRhdGEgPSAuLCB2YXIuZXF1YWw9IGkkcC52YWx1ZT4wLjA1KSAlPiUKICAjd2lsY294LnRlc3QoQWIudW5pdHNfbG9nIH4gcGhlbm8sIGRhdGEgPSAuKSAlPiUjLCAKICAgICAgICAgICAgICAjY29uZi5pbnQ9VFJVRSkgJT4lIAogIGNvci50ZXN0KH4gQWIudW5pdHMgKyBlZGFkLCAKICAgICAgICAgICBkYXRhID0gLiwgbWV0aG9kID0gInNwZWFybWFuIikgJT4lIAogIGJyb29tOjp0aWR5KCkgJT4lICAjJT4lIGZvcm1hdChkaWdpdHM9MikKICAjZHBseXI6OnNlbGVjdCgtc3RhcnRzX3dpdGgoImVzdGltYXRlIikpICU+JSAKICBtdXRhdGUoaWdnPWxldmVscyhmKVtsXSwjbAogICAgICAgICBsYWI9IHBhc3RlMCgjInQ9Iiwjc2hvdWxkIGJlIGRvbmUgLT4gbWl4IHZhcmlhbmNlIGVxdWFsaXR5IHRlc3QKICAgICAgICAgICAgICAgICAgICAgIyJXPSIsI25vbi1wYXJhbWV0cmljIHVzZWQgaW4gbGl0ZXJhdHVyZQogICAgICAgICAgICAgICAgICAgICAjIlM9IixmJHN0YXRpc3RpYywiLCByaG89IgogICAgICAgICAgICAgICAgICAgICAicmhvPSIsZXN0aW1hdGUgJT4lIGZvcm1hdChkaWdpdHM9MiksCiAgICAgICAgICAgICAgICAgICAgICJcblAiLGlmZWxzZShwLnZhbHVlPDAuMDAxLCI8MC4wMDEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKCI9IixwLnZhbHVlICU+JSBmb3JtYXQoZGlnaXRzPTIpKSkKICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICApCgpzdHQgPC0gc3R0ICU+JSB1bmlvbihqKQoKfQoKc3R0IDwtIHN0dCAlPiUgYXJyYW5nZShpZ2cpICU+JSBkcGx5cjo6c2VsZWN0KGlnZyxldmVyeXRoaW5nKCkpICU+JSAKICBtdXRhdGUoeD0uMSwKICAgICAgICAgeT01NSkKCiMgcGxvdAphZ2UgJT4lICNmaWx0ZXIoaWdnPT1sZXZlbHMoZilbMV0pICU+JSAKICBnZ3Bsb3QoYWVzKEFiLnVuaXRzLGVkYWQpKSArCiAgZ2VvbV9wb2ludCgpICsKICBzY2FsZV94X2xvZzEwKCkgKwogICNzY2FsZV95X2xvZzEwKCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9IGxtLHNlPUYsY29sPSJncmV5NTAiLGx3ZD0uNSkgKwogICNnZW9tX3Ntb290aChtZXRob2QgPSBsb2VzcyxzZT1GLGNvbD0iZ3JleTUwIixsd2Q9LjUpICsKICBnZW9tX3RleHQoYWVzKHgseSxsYWJlbD1sYWIpLGRhdGEgPSBzdHQsCiAgICAgICAgICAgIHZqdXN0PS41LGhqdXN0PTAuMDUsc2l6ZT0zLjUpICsKICBmYWNldF9ncmlkKH5pZ2cKICAgICAgICAgICAgICMsc2NhbGVzID0gImZyZWUiCiAgICAgICAgICAgICApICsKICAjZmFjZXRfd3JhcCh+aWdnLG5jb2wgPSA1KQogIGxhYnModGl0bGU9IkNvcnJlbGF0aW9uIGJldHdlZW4gQVUgYW5kIHBhcmFzaXRlbWlhIHBlciBJZ0cgc3VidHlwZSIpCmBgYAoKCiMjIEFzc29jaWF0aW9uCgotIG91dGNvbWU6IHN5bXB0b21hdGljIFAuZi4gbWFsYXJpYQoKIyMjIE9uIFBvd2VyIGFuZCBzYW1wbGUgc2l6ZQoKIyMjIyBtaW5pbXVtIG51bWJlciBvZiBjYW5kaWRhdGUgcHJlZGljdG9ycwoKYGBge3J9CmNhc2U9MjAKY3RybD0yNAptX2M9bWluKGNhc2UsY3RybCkgI2xpbWl0aW5nIHNhbXBsZSBzaXplCnA9NSAjY3VycmVudCBudW1iZXIgb2YgcHJlZGljdG9ycwojcm91bmQobV9jLzE1KSAjCnA8bV9jLzE1CmBgYAoKLSBHaXZlbiB0aGUgY3VycmVudCBfbGltaXRpbmcgc2FtcGxlIHNpemVfLCBmb3IgYSByZWxpYWJsZSBtb2RlbCB0aGUgbnVtYmVyIG9mIF9fY2FuZGlkYXRlIHByZWRpY3RvcnMgbXVzdCBiZSBsb3dlciB0aGFuIGByIHJvdW5kKG1fYy8xNSlgLl9fCgojIyMjIG1pbmltdW0gbnVtYmVyIG9mIGNhc2VzCgpgYGB7cn0Kaz01ICNudW1iZXIgb2YgY292YXJpYXRlcwpwPSAwLjQgIyBwcmV2YWxlbmNlIG9mIG91dGNvbWUKbl94PTEwKmsvcApgYGAKCi0gR2l2ZW4gdGhlIF9fbWVhc3VyZWQgY292YXJpYXRlc19fIGFuZCBfX3ByZXZhbGVuY2VfXyBvZiBtb2RlbGVkIG91dGNvbWUsIHRoZSBfX21pbmltdW0gc2FtcGxlIHNpemUgcmVxdWlyZWQgaXMgYHIgbl94YF9fLgoKYGBge3J9CiMgZXhwb3NpdGlvbjogc3ltcHRvbWF0aWMgbWFsYXJpYSAoNjAlIGFzeW1wdCBpbiBQZikKIwojIGdpdmVuIHRoZSBwcm9wb3J0aW9uIChwcmV2YWxlbmNlKSByZWxldmFudCBPUiBhbmQgcmVxdWlyZWQgcG93ZXIsIAojIG9idGFpbiB0aGUgc2FtcGxlIHNpemUgcmVxdWlyZWQKcD0wLjQwICNwcm9wb3J0aW9uIG9mIGV4cG9zdXJlIGluIGdlbmVyYWwgcG9wdWxhdGlvbiBPUiBvdXRjb21lIHByb3ZhbGVuY2UKIyhPUj1wQSooMS1wQikvcEIvKDEtcEEpKSAjIDIKT1I9LjUgI2h5cG90aGV0aWNhbCBPUgojCmthcHBhPTEgIyBzYW1wbGluZyByYXRpbyBiZXR3ZWVuIGNhc2U6Y29udHJvbAphbHBoYT0wLjA1ICN0eXBlIDEgZXJyb3IgKGZhbHNlIHBvc2l0aXZlcykKYmV0YT0wLjIwICNwb3dlcj0xLWJldGEgI3R5cGUgMiBlcnJvciAoZmFsc2UgbmVnYXRpdmVzKQojKG49ICgoKDEra2FwcGEpXjIpKigocW5vcm0oMS1hbHBoYS8yKStxbm9ybSgxLWJldGEpKV4yKSkgLyAoa2FwcGEqcCooMS1wKSooKGxvZyhPUikpXjIpKSApCm4xPSAoNCooKHFub3JtKDEtYWxwaGEvMikrcW5vcm0oMS1iZXRhKSleMikpIC8gKHAqKDEtcCkqKChsb2coT1IpKV4yKSkgCiNjZWlsaW5nKG4pICMgQWZyaWRpIDIyMCwgQnJhZ2dhIDI2MywgU3RhbmlzaWMgMjA2LCBNZWRlaXJvcyAyOCsyNApgYGAKCi0gR2l2ZW4gdGhlIGtub3duIF9fcHJldmFsZW5jZV9fIG9mIHN5bXB0b21hdGljIG1hbGFyaWEgaW4gSXF1aXRvcyBhbmQgYSByZWxldmFudCBfX09kZHMgUmF0aW9fXyByZXBvcnRlZCBpbiBsaXRlcmF0dXJlLCBhIF9fc2FtcGxlIHNpemUgb2YgYHIgY2VpbGluZyhuMSlgX18gd291bGQgYmUgcmVxdWlyZWQgdG8gYWNoaWV2ZSBhIF9fcG93ZXIgODAlX18uCgpgYGB7cn0KIyBnaXZlbiB0aGUgYXZhaWxhYmxlIHNhbXBsZSBzaXplIGFuZCBvYnRhaW5lZCBPZGRzIFJhdGlvLCAKIyBvYnRhaW4gdGhlIGFjdHVhbCBwb3dlcgpuMj0gNDQKIyhPUj0uNSkKej1sb2coT1IpKnNxcnQobjIpL3NxcnQoKCgxK2thcHBhKV4yKS8oa2FwcGEqcCooMS1wKSkpClBvd2VyPXBub3JtKHotcW5vcm0oMS1hbHBoYS8yKSkrcG5vcm0oLXotcW5vcm0oMS1hbHBoYS8yKSkKYGBgCgotIEZvbGxvd2luZyB0aGUgc2FtZSBtZXRob2QsIGdpdmVuIHRoZSBfX2N1cnJlbnQgc2FtcGxlIHNpemVfXywgdGhpcyBhbmFseXNpcyBoYXZlIGEgX19wb3dlciBvZiBgciBmb3JtYXQoUG93ZXIqMTAwLGRpZ2l0cyA9IDQpYCVfXy4KCmBgYHtyLGV2YWw9RkFMU0UsZWNobz1GQUxTRX0KI2h0dHA6Ly9wb3dlcmFuZHNhbXBsZXNpemUuY29tL0NhbGN1bGF0b3JzL1Rlc3QtT2Rkcy1SYXRpby9FcXVhbGl0eQojIFRFU1QgT0RERCBFUVVBTElUWSBCRVRXRUVOIFRXTyBHUk9VUFMKcEE9MC40MCAjcHJvYmFiaWxpdHkgb2YgdGhlIG91dGNvbWUgaW4gZ3JvdXAgQQpwQj0wLjI1ICNwcm9iYWJpbGl0eSBvZiB0aGUgb3V0Y29tZSBpbiBncm91cCBCCmthcHBhPTEgIyBzYW1wbGluZyByYXRpbwphbHBoYT0wLjA1ICNlcnJvciByYXRlCmJldGE9MC4yMCAjcG93ZXI9MS1iZXRhCihPUj1wQSooMS1wQikvcEIvKDEtcEEpKSAjIDIKKG5CPSgxLyhrYXBwYSpwQSooMS1wQSkpKzEvKHBCKigxLXBCKSkpKigocW5vcm0oMS1hbHBoYS8yKStxbm9ybSgxLWJldGEpKS9sb2coT1IpKV4yKQpjZWlsaW5nKG5CKSAjIDE1Ngp6PWxvZyhPUikqc3FydChuQikvc3FydCgxLyhrYXBwYSpwQSooMS1wQSkpKzEvKHBCKigxLXBCKSkpCihQb3dlcj1wbm9ybSh6LXFub3JtKDEtYWxwaGEvMikpK3Bub3JtKC16LXFub3JtKDEtYWxwaGEvMikpKQpgYGAKCgojIyMgVGlkeSB1cAoKIyMjIyBpbm11bm8KCmBgYHtyfQojbGlicmFyeSh0aWR5dmVyc2UpCgptbW8gPC0gbWNvICU+JSAjZmlsdGVyKGlnZz09ImlnZyIpICU+JSAKICBtdXRhdGUocGhlbm89YXMuZmFjdG9yKHBoZW5vKSkgJT4lIAogIG11dGF0ZShwaGVubz1mb3JjYXRzOjpmY3RfcmVsZXZlbChwaGVubywic3ltcHRvbWF0aWMiKSkgJT4lIAogIG11dGF0ZShwaGVuby5udW09aWZlbHNlKHBoZW5vPT0iYXN5bXB0b21hdGljIiwwLDEpKSAlPiUgCiAgbXV0YXRlKHBoZW5vLmxvZz1pZmVsc2UocGhlbm89PSJhc3ltcHRvbWF0aWMiLEZBTFNFLFRSVUUpKQpgYGAKCi0gdGhlIG9ubHkgcmVhZHMgYXZhaWxhYmxlIGZvciBzYW1wbGUgYDIyMzVgIGFyZSBmb3IgdGhlIGFzeW1wdG9tYXRpYyBzdGF0ZSEKCmBgYHtyLGV2YWw9RkFMU0V9CmNvdmEgJT4lIApjb3ZiICU+JSAKY292eCAlPiUgCiAgZmlsdGVyKGNvZGlnbz09IjIyMzUiIHwgY29kaWdvPT0iMzA1MyIgfCBjb2RpZ289PSI5MTY1IiB8IGNvZGlnbz09Ijk4MDEiKSAlPiUgCiAgYXJyYW5nZShjb2RpZ28pICMlPiUgCiAgI2RwbHlyOjpzZWxlY3QoY29kaWdvLGVkYWQsc2V4byxwYXIsZXZlcnl0aGluZygpKQpgYGAKCmBgYHtyLGV2YWw9RkFMU0V9CiMjIGFkZCBjb3ZhcmlhdGVzCmZ1bGxfam9pbihtbW8sbWN2LGJ5PWMoIklEIiwicGFyIiwicGhlbm8iKSkgJT4lIAogIGZpbHRlcihJRD09IjIyMzUiIHwgSUQ9PSIzMDUzIiB8IElEPT0iOTE2NSIgfCBJRD09Ijk4MDEiKSAlPiUgCiAgYXJyYW5nZShJRCkKYGBgCgojIyMjIGNvdmFyaWF0ZXMKCi0gTk9UQTogMjIzNSB0aWVuZSBkb3Mgb2JzZXJ2YWNpb25lcyBlbiBtYXRyaXogZGUgY292YXJpYWJsZXMsIHBlcm8gZW4gdGVtcGxhdGVzIHNvbG8gaGEgc2lkbyBpZGVudGlmaWNhZG8gY29tbyBhc2ludG9tw6F0aWNvIQoKYGBge3J9Cm1jdl90IDwtIG1jdiAlPiUgI2ZpbHRlcihpZ2c9PSJpZ2ciKSAlPiUgCiAgbXV0YXRlKHBoZW5vPWFzLmZhY3RvcihwaGVubykpICU+JSAKICBtdXRhdGUocGhlbm89Zm9yY2F0czo6ZmN0X3JlbGV2ZWwocGhlbm8sInN5bXB0b21hdGljIikpICU+JSAKICBtdXRhdGUocGhlbm8ubnVtPWlmZWxzZShwaGVubz09ImFzeW1wdG9tYXRpYyIsMCwxKSkgJT4lIAogIG11dGF0ZShwaGVuby5sb2c9aWZlbHNlKHBoZW5vPT0iYXN5bXB0b21hdGljIixGQUxTRSxUUlVFKSkKYGBgCgoKIyMjIyBpbm11bm8gcGVyIHN1YmNsYXNzCgpgYGB7cn0KIyMjIE1VTFRJUExFIExPR0lTVElDIFJFR1JFU1NJT04KbW1vX3ggPC0gbW1vICU+JSAKICBkcGx5cjo6c2VsZWN0KElELAogICAgICAgICAgICAgICAgI2NvZGUsCiAgICAgICAgICAgICAgICAjcGhlbm8sCiAgICAgICAgICAgICAgICBpZ2cKICAgICAgICAgICAgICAgICxBYi51bml0cwogICAgICAgICAgICAgICAgIyxBYi51bml0c19sb2cKICAgICAgICAgICAgICAgICxwaGVuby5udW0jLHBoZW5vLmxvZyAjIDE6IHN5bXB0b21hdGljLCAwOjogYXN5bXB0b21hdGljCiAgICAgICAgICAgICAgICApICU+JSAKICBzcHJlYWQoaWdnCiAgICAgICAgICxBYi51bml0cwogICAgICAgICAjLEFiLnVuaXRzX2xvZwogICAgICAgICApCgojbW1vX3gub21pdCA9IG5hLm9taXQobW1vX3gpCmBgYAoKIyMjIyBhZGQgY292YXJpYXRlcwoKYGBge3J9Cm1sciA8LSBtY3ZfdCAlPiUgCiAgZHBseXI6OnNlbGVjdChJRCxwaGVuby5udW0sIGVkYWQsIHNleG8sIHBhcikgJT4lIAogIGlubmVyX2pvaW4obW1vX3gsYnk9YygiSUQiLCJwaGVuby5udW0iKSkKCm1scl9uYSA9IG5hLm9taXQobWxyKQoKI2RkIDwtIHJtczo6ZGF0YWRpc3QobWxyX25hKTsgb3B0aW9ucyhkYXRhZGlzdD0nZGQnKQpgYGAKCmBgYHtyfQojIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzc1MDU1NDcvZGV0YWNoLWFsbC1wYWNrYWdlcy13aGlsZS13b3JraW5nLWluLXIKCmRldGFjaEFsbFBhY2thZ2VzIDwtIGZ1bmN0aW9uKCkgewoKICBiYXNpYy5wYWNrYWdlcyA8LSBjKCJwYWNrYWdlOnN0YXRzIiwKICAgICAgICAgICAgICAgICAgICAgICJwYWNrYWdlOmdyYXBoaWNzIiwKICAgICAgICAgICAgICAgICAgICAgICJwYWNrYWdlOmdyRGV2aWNlcyIsCiAgICAgICAgICAgICAgICAgICAgICAicGFja2FnZTp1dGlscyIsCiAgICAgICAgICAgICAgICAgICAgICAicGFja2FnZTpkYXRhc2V0cyIsCiAgICAgICAgICAgICAgICAgICAgICAicGFja2FnZTptZXRob2RzIiwKICAgICAgICAgICAgICAgICAgICAgICJwYWNrYWdlOmJhc2UiKQoKICBwYWNrYWdlLmxpc3QgPC0gc2VhcmNoKClbCiAgICBpZmVsc2UoCiAgICAgIHVubGlzdCgKICAgICAgICBncmVnZXhwcigicGFja2FnZToiLHNlYXJjaCgpKQogICAgICAgICk9PTEsVFJVRSxGQUxTRQogICAgICApCiAgICBdCgogIHBhY2thZ2UubGlzdCA8LSBzZXRkaWZmKHBhY2thZ2UubGlzdCxiYXNpYy5wYWNrYWdlcykKCiAgaWYgKGxlbmd0aChwYWNrYWdlLmxpc3QpPjApICAKICAgIGZvciAocGFja2FnZSBpbiBwYWNrYWdlLmxpc3QpIAogICAgICBkZXRhY2gocGFja2FnZSwgY2hhcmFjdGVyLm9ubHk9VFJVRSkKCn0KCmRldGFjaEFsbFBhY2thZ2VzKCkKYGBgCgoKYGBge3IsIG1lc3NhZ2U9RkFMU0V9CiMgRVhQTEFJTkVEOiBodHRwczovL3N0YXRzLnN0YWNrZXhjaGFuZ2UuY29tL3F1ZXN0aW9ucy82NDc4OC9pbnRlcnByZXRpbmctYS1sb2dpc3RpYy1yZWdyZXNzaW9uLW1vZGVsLXdpdGgtbXVsdGlwbGUtcHJlZGljdG9ycwoKbGlicmFyeSh0aWR5dmVyc2UpCm1tb194X3JtcyA8LSBtbHJfbmEgJT4lIAogIG11dGF0ZShpZ2dfYz1udGlsZShpZ2csMyksCiAgICAgICAgIGlnZzFfYz1udGlsZShpZ2cxLDMpLAogICAgICAgICBpZ2cyX2M9bnRpbGUoaWdnMiwzKSwKICAgICAgICAgaWdnM19jPW50aWxlKGlnZzMsMyksCiAgICAgICAgIGlnZzRfYz1udGlsZShpZ2c0LDMpCiAgICAgICAgICkgJT4lIAogIG11dGF0ZShpZ2dfYz1hcy5mYWN0b3IoaWdnX2MpLAogICAgICAgICBpZ2cxX2M9YXMuZmFjdG9yKGlnZzFfYyksCiAgICAgICAgIGlnZzJfYz1hcy5mYWN0b3IoaWdnMl9jKSwKICAgICAgICAgaWdnM19jPWFzLmZhY3RvcihpZ2czX2MpLAogICAgICAgICBpZ2c0X2M9YXMuZmFjdG9yKGlnZzRfYykpICU+JSAKICBtdXRhdGUoaWdnX2Q9aWdnLzEwLAogICAgICAgICBpZ2cxX2Q9aWdnMS8xMCwKICAgICAgICAgaWdnMl9kPWlnZzIvMTAsCiAgICAgICAgIGlnZzNfZD1pZ2czLzEwLAogICAgICAgICBpZ2c0X2Q9aWdnNC8xMCkgJT4lIAogIG11dGF0ZShpZ2dfbD1sb2cxMChpZ2cpLAogICAgICAgICBpZ2cxX2w9bG9nMTAoaWdnMSksCiAgICAgICAgIGlnZzJfbD1sb2cxMChpZ2cyKSwKICAgICAgICAgaWdnM19sPWxvZzEwKGlnZzMpLAogICAgICAgICBpZ2c0X2w9bG9nMTAoaWdnNCkpICMlPiUgCiAgI2RwbHlyOjpzZWxlY3QoSUQscGhlbm8ubnVtLAogICAjICAgICAgICAgICAgIGlnZz1pZ2dfYywKICAgICMgICAgICAgICAgICBpZ2cxPWlnZzFfYywKICAgICAjICAgICAgICAgICBpZ2cyPWlnZzJfYywKICAgICAgIyAgICAgICAgICBpZ2czPWlnZzNfYywKICAgICAgICMgICAgICAgICBpZ2c0PWlnZzRfYwogICAgICAgICMgICAgICAgICkKCmRkIDwtIHJtczo6ZGF0YWRpc3QobW1vX3hfcm1zKTsgb3B0aW9ucyhkYXRhZGlzdD0nZGQnKQpgYGAKCiMjIyMgZGF0YSB3aXRoIG1pc3NpbmdzCgpgYGB7cn0KbW1vICU+JSBkcGx5cjo6Y291bnQoaWdnKQpgYGAKCiMjIyBVbml2YXJpYXRlCgojIyMjIFBSRTogdW5pdmFyaWF0ZQoKYGBge3IsZXZhbD1GQUxTRSxlY2hvPUZBTFNFfQp0cm0gPC0gZGF0YV9mcmFtZShpZ2c9YXMuY2hhcmFjdGVyKCksCiAgICAgICAgICAgICAgICAgIHRlcm09YXMuY2hhcmFjdGVyKCksCiAgICAgICAgICAgICAgICAgIGVzdGltYXRlPWFzLmRvdWJsZSgpLAogICAgICAgICAgICAgICAgICBzdGQuZXJyb3I9YXMuZG91YmxlKCksCiAgICAgICAgICAgICAgICAgIHN0YXRpc3RpYz1hcy5kb3VibGUoKSwKICAgICAgICAgICAgICAgICAgcC52YWx1ZT1hcy5kb3VibGUoKSkKCmR2bSA8LSBkYXRhX2ZyYW1lKGlnZz1hcy5jaGFyYWN0ZXIoKSwKICAgICAgICAgICAgICAgICAgbnVsbC5kZXZpYW5jZT0gYXMuZG91YmxlKCksCiAgICAgICAgICAgICAgICAgIGRmLm51bGw9IGFzLmludGVnZXIoKSwKICAgICAgICAgICAgICAgICAgbG9nTGlrPSBhcy5kb3VibGUoKSwKICAgICAgICAgICAgICAgICAgQUlDPSBhcy5kb3VibGUoKSwKICAgICAgICAgICAgICAgICAgQklDPSBhcy5kb3VibGUoKSwKICAgICAgICAgICAgICAgICAgZGV2aWFuY2U9IGFzLmRvdWJsZSgpLAogICAgICAgICAgICAgICAgICBkZi5yZXNpZHVhbD0gYXMuaW50ZWdlcigpKQoKYW92IDwtIGRhdGFfZnJhbWUoaWdnPWFzLmNoYXJhY3RlcigpLAogICAgICAgICAgICAgICAgICBSZXNpZC4uRGY9YXMuZG91YmxlKCksCiAgICAgICAgICAgICAgICAgIFJlc2lkLi5EZXY9YXMuZG91YmxlKCksCiAgICAgICAgICAgICAgICAgIGRmPWFzLmRvdWJsZSgpLAogICAgICAgICAgICAgICAgICBEZXZpYW5jZT1hcy5kb3VibGUoKSwKICAgICAgICAgICAgICAgICAgcC52YWx1ZT1hcy5kb3VibGUoKSkKCmZvciAoaSBpbiAxOmxlbmd0aChsZXZlbHMoZikpKSB7CiAgCm1vZGVsIDwtIGdsbShwaGVubyB+IEFiLnVuaXRzX2xvZywKICAgICAgICAgICAgZGF0YT0gbW1vICU+JSBmaWx0ZXIoaWdnPT1sZXZlbHMoZilbaV0pLAogICAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbChsaW5rPSJsb2dpdCIpKQoKdHJtIDwtIHRybSAlPiUgCiAgdW5pb24oCiAgICBicm9vbTo6dGlkeShtb2RlbCkgJT4lIAogICAgICBtdXRhdGUoaWdnPWxldmVscyhmKVtpXSkgJT4lIAogICAgICBkcGx5cjo6c2VsZWN0KGlnZyx0ZXJtLGV2ZXJ5dGhpbmcoKSkKICApCgpkdm0gPC0gZHZtICU+JSAKICB1bmlvbigKICAgIGJyb29tOjpnbGFuY2UobW9kZWwpICU+JSAKICAgICAgbXV0YXRlKGlnZz1sZXZlbHMoZilbaV0pICU+JSAKICAgICAgZHBseXI6OnNlbGVjdChpZ2csZXZlcnl0aGluZygpKQogICkKCmJyb29tOjpnbGFuY2UobW9kZWwpICMgVEVTVCBBSUMKCmFvdiA8LSBhb3YgJT4lIAogIHVuaW9uKAogICAgYW5vdmEobW9kZWwsCiAgICAgICAgICB1cGRhdGUobW9kZWwsIH4xKSwKICAgICAgICAgIHRlc3Q9IkNoaXNxIikgJT4lIAogICAgICBicm9vbTo6dGlkeSgpICU+JSAKICAgICAgbXV0YXRlKGlnZz1sZXZlbHMoZilbaV0pICU+JSAKICAgICAgZHBseXI6OnNlbGVjdChpZ2csZXZlcnl0aGluZygpKQogICkKCn0KCiNkdm0gJT4lIGFycmFuZ2UoaWdnKQojdHJtICU+JSBhcnJhbmdlKGlnZyx0ZXJtKSAlPiUgIy4kdGVybQojICBmaWx0ZXIodGVybSE9IihJbnRlcmNlcHQpIikgJT4lIAojICBkcGx5cjo6c2VsZWN0KC10ZXJtKQojYW92ICU+JSBhcnJhbmdlKGlnZyxSZXNpZC4uRGYpCmBgYAoKYGBge3IsZXZhbD1GQUxTRSxlY2hvPUZBTFNFfQojc3VtbWFyeShtb2RlbCkKI21vZGVsJGNvZWZmaWNpZW50cwojY29uZmludChtb2RlbCkKZXhwKG1vZGVsJGNvZWZmaWNpZW50cykgICAgICAgICAjIGV4cG9uZW50aWF0ZWQgY29lZmZpY2llbnRzCmV4cChjb25maW50KG1vZGVsKSkgICAgICAgICAgICAgIyA5NSUgQ0kgZm9yIGV4cG9uZW50aWF0ZWQgY29lZmZpY2llbnRzCmBgYAoKYGBge3IsZmlnLndpZHRoPTEwLGZpZy5oZWlnaHQ9Mi41LGV2YWw9RkFMU0UsZWNobz1GQUxTRX0KI21vZGVsID0gZ2xtKHBoZW5vIH4gQWIudW5pdHMsCiMgICAgICAgICAgICBkYXRhPSBtbW8sCiMgICAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbChsaW5rPSJsb2dpdCIpKQpnZ3Bsb3QobW1vLCBhZXMoeD1BYi51bml0cywgeT1waGVuby5udW0pKSArIAogIGdlb21fcG9pbnQoYWxwaGE9LjMpICsgCiAgc3RhdF9zbW9vdGgobWV0aG9kPSJnbG0iLCBtZXRob2QuYXJncz1saXN0KGZhbWlseT0iYmlub21pYWwiKSwgc2U9VFJVRSkgKwogIGZhY2V0X2dyaWQofmlnZyxzY2FsZXMgPSAiZnJlZSIpICsKICAjc2NhbGVfeF9sb2cxMCgpICsgI2JldHRlciBtb2RlbCBieSBtZWFucyBvZiBBSUMKICBsYWJzKHRpdGxlPSBleHByZXNzaW9uKHBhc3RlKCJBbnRpYm9keSByZXNwb25zZXMgYXNzb2NpYXRlZCB3aXRoIHN1c2NlcHRpYmlsaXR5IHRvIHN5bXB0b21hdGljIG1hbGFyaWEiKSkpICsKICAjdG8gcHJvdGVjdGlvbiBhZ2FpbnN0CiAgI3dpdGggc3VzY2VwdGliaWxpdHkgdG8KICB5bGFiKCJQcm9iYWJpbGl0eSIpCmBgYAoKIyMjIyMgYWdlCgpgYGB7cixldmFsPUZBTFNFLGVjaG89RkFMU0V9Cm1vZDEgPSBybXM6OmxybShhcy5mYWN0b3IocGhlbm8ubnVtKSB+IGVkYWQKICAgICAgICAgICAgICAgICxkYXRhPW1tb194X3JtcywgeD1UUlVFLCB5PVRSVUUpCm1vZDEKcGFzdGUoIkFJQz0iLEFJQyhtb2QxKSkKc3VtbWFyeShtb2QxKQojcGxvdChzdW1tYXJ5KG1vZDEpLCBsb2c9VFJVRSxtYWluID0gImxvZyBPZGRzIFJhdGlvIixjZXgubWFpbiA9IDApCmBgYAoKIyMjIyMgc2V4CgpgYGB7cixldmFsPUZBTFNFLGVjaG89RkFMU0V9Cm1vZDEgPSBybXM6OmxybShhcy5mYWN0b3IocGhlbm8ubnVtKSB+IHNleG8KICAgICAgICAgICAgICAgICxkYXRhPW1tb194X3JtcywgeD1UUlVFLCB5PVRSVUUpCm1vZDEKcGFzdGUoIkFJQz0iLEFJQyhtb2QxKSkKc3VtbWFyeShtb2QxKQojcGxvdChzdW1tYXJ5KG1vZDEpLCBsb2c9VFJVRSxtYWluID0gImxvZyBPZGRzIFJhdGlvIixjZXgubWFpbiA9IDApCmBgYAoKIyMjIyMgcGFyYXNpdGVtaWEKCmBgYHtyLGV2YWw9RkFMU0UsZWNobz1GQUxTRX0KbW9kMSA9IHJtczo6bHJtKGFzLmZhY3RvcihwaGVuby5udW0pIH4gcGFyICMrIGlnZzEgKyBpZ2cyICsgaWdnMyArIGlnZzQKICAgICAgICAgICAgICAgICxkYXRhPW1tb194X3JtcywgeD1UUlVFLCB5PVRSVUUpCm1vZDEKcGFzdGUoIkFJQz0iLEFJQyhtb2QxKSkKc3VtbWFyeShtb2QxKQpgYGAKCiMjIyMjIGlnZwoKYGBge3IsZXZhbD1GQUxTRSxlY2hvPUZBTFNFfQptb2QxID0gcm1zOjpscm0oYXMuZmFjdG9yKHBoZW5vLm51bSkgfiBpZ2cgIysgaWdnMSArIGlnZzIgKyBpZ2czICsgaWdnNAogICAgICAgICAgICAgICAgLGRhdGE9bW1vX3hfcm1zLCB4PVRSVUUsIHk9VFJVRSkKbW9kMQpwYXN0ZSgiQUlDPSIsQUlDKG1vZDEpKQpzdW1tYXJ5KG1vZDEpCmBgYAoKIyMjIyMgaWdnMQoKYGBge3IsZXZhbD1GQUxTRSxlY2hvPUZBTFNFfQptb2QxID0gcm1zOjpscm0oYXMuZmFjdG9yKHBoZW5vLm51bSkgfiBpZ2cxICMrIGlnZzEgKyBpZ2cyICsgaWdnMyArIGlnZzQKICAgICAgICAgICAgICAgICxkYXRhPW1tb194X3JtcywgeD1UUlVFLCB5PVRSVUUpCm1vZDEKcGFzdGUoIkFJQz0iLEFJQyhtb2QxKSkKc3VtbWFyeShtb2QxKQpgYGAKCiMjIyMjIGlnZzIKCmBgYHtyLGV2YWw9RkFMU0UsZWNobz1GQUxTRX0KbW9kMSA9IHJtczo6bHJtKGFzLmZhY3RvcihwaGVuby5udW0pIH4gaWdnMiAjKyBpZ2cxICsgaWdnMiArIGlnZzMgKyBpZ2c0CiAgICAgICAgICAgICAgICAsZGF0YT1tbW9feF9ybXMsIHg9VFJVRSwgeT1UUlVFKQptb2QxCnBhc3RlKCJBSUM9IixBSUMobW9kMSkpCnN1bW1hcnkobW9kMSkKYGBgCgojIyMjIyBpZ2czCgpgYGB7cixldmFsPUZBTFNFLGVjaG89RkFMU0V9Cm1vZDEgPSBybXM6OmxybShhcy5mYWN0b3IocGhlbm8ubnVtKSB+IGlnZzMgIysgaWdnMSArIGlnZzIgKyBpZ2czICsgaWdnNAogICAgICAgICAgICAgICAgLGRhdGE9bW1vX3hfcm1zLCB4PVRSVUUsIHk9VFJVRSkKbW9kMQpwYXN0ZSgiQUlDPSIsQUlDKG1vZDEpKQpzdW1tYXJ5KG1vZDEpCmBgYAoKIyMjIyMgaWdnNAoKYGBge3IsZXZhbD1GQUxTRSxlY2hvPUZBTFNFfQptb2QxID0gcm1zOjpscm0oYXMuZmFjdG9yKHBoZW5vLm51bSkgfiBpZ2c0ICMrIGlnZzEgKyBpZ2cyICsgaWdnMyArIGlnZzQKICAgICAgICAgICAgICAgICxkYXRhPW1tb194X3JtcywgeD1UUlVFLCB5PVRSVUUpCm1vZDEKcGFzdGUoIkFJQz0iLEFJQyhtb2QxKSkKc3VtbWFyeShtb2QxKQpgYGAKCiMjIyMjIElnRyBtb2RlbAoKYGBge3IsZXZhbD1GQUxTRSxlY2hvPUZBTFNFLGluY2x1ZGU9RkFMU0V9CiMjIyBNWSBQUk9DRURVUkUKbW9kZWwgPSBnbG0ocGhlbm8ubnVtIH4gaWdnICsgaWdnMSArIGlnZzIgKyBpZ2czICsgaWdnNCArIGVkYWQgKyBzZXhvCiAgICAgICAgICAgICxkYXRhPSBtbW9feF9ybXMsCiAgICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKGxpbms9ImxvZ2l0IikjLG5hLmFjdGlvbiA9IG5hLm9taXQKICAgICAgICAgICAgKQoKI3N1bW1hcnkobW9kZWwpCgojYnJvb206OmF1Z21lbnQobW9kZWwpCnBhc3RlKCJBSUM9IixBSUMobW9kZWwpKQojYnJvb206OmdsYW5jZShtb2RlbCkgIyBURVNUIEFJQwojYnJvb206OnRpZHkobW9kZWwpCgojbW9kZWwkY29lZmZpY2llbnRzCiNjb25maW50KG1vZGVsKQpleHAobW9kZWwkY29lZmZpY2llbnRzKSAgICAgICAgICMgZXhwb25lbnRpYXRlZCBjb2VmZmljaWVudHMgIyBPRERTIFJBVElPCmV4cChjb25maW50KG1vZGVsKSkgICAgICAgICAgICAgIyA5NSUgQ0kgZm9yIGV4cG9uZW50aWF0ZWQgY29lZmZpY2llbnRzCmBgYAoKYGBge3IsZmlnLmhlaWdodD0yLjIsZmlnLndpZHRoPTMuOCxldmFsPUZBTFNFLGVjaG89RkFMU0UsaW5jbHVkZT1GQUxTRX0KI2N1dChzZXEoLjAxLDEsYnk9LjAwMSksYnJlYWtzID0gMykKI3F1YW50aWxlKHNlcSguMDEsLjEsYnk9LjAwMSkpCiNxdWFudGlsZShzZXEoLjAxLC4xLGJ5PS4wMDEpLHByb2JzID0gYygwLDAuMzMsMC42NiwxKSkKR0dhbGx5OjpnZ2NvZWYobW9kZWwsZXhwb25lbnRpYXRlID0gVCwKICAgICAgICAgICAgICAgZXhjbHVkZV9pbnRlcmNlcHQgPSBULAogICAgICAgICAgICAgICBlcnJvcmJhcl9oZWlnaHQgPSAuMjUsCiAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IGVzdGltYXRlLCB5ID0gdGVybSMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICNzaXplID0gcC52YWx1ZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2NvbG91cj1wLnZhbHVlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkgKwogICNzY2FsZV9zaXplX2NvbnRpbnVvdXModHJhbnMgPSAicmV2ZXJzZSIjLAogICAgICAgICAgICAgICAgICAgICAgICAjbGFiZWxzID0gYXMubnVtZXJpYyhxdWFudGlsZShzZXEoLjAxLC4xLGJ5PS4wMDEpLAogICAgICAgICAgICAgICAgICAgICAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9icyA9IGMoMCwwLjMzLDAuNjYsMSkpCiAgICAgICAgICAgICAgICAgICAgICAgICMgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgIyxsaW1pdHMgPSBjKC4xLC4wMDEpCiAgICMgICAgICAgICAgICAgICAgICAgICApICsKICAjc2NhbGVfY29sb3VyX3ZpcmlkaXNfYyh0cmFucyA9ICJyZXZlcnNlIiMsCiAgICAgICAgICAgICAgICAgICAgICAgICNsYWJlbHMgPSBhcy5udW1lcmljKHF1YW50aWxlKHNlcSguMDEsLjEsYnk9LjAwMSksCiAgICAgICAgICAgICAgICAgICAgICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2JzID0gYygwLDAuMzMsMC42NiwxKSkKICAgICAgICAgICAgICAgICAgICAgICAgIyAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgICAgICAgICAjLGxpbWl0cyA9IGMoLjEsLjAwMSkKICAgICMgICAgICAgICAgICAgICAgICAgICkgKwogICNzY2FsZV94X2xvZzEwKCkgKwogICNjb29yZF90cmFucyh4PSJsb2cxMCIpICsKICAjY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKC0xMCwxMDApKSArCiAgbGFicyh0aXRsZT0iU3VzY2VwdGliaWxpdHkgdG8gc3ltcHRvbWF0aWMgbWFsYXJpYSIpICsKICAjUHJvdGVjdGlvbiBhZ2FpbnN0CiAgI1N1c2NlcHRpYmlsaXR5IHRvCiAgI0xvd2VyIHJpc2sgdG8gCiAgeGxhYigib2RkcyByYXRpbyAobG9nIHNjYWxlKSIpICsKICB5bGFiKCJhbnRpYm9keSBzdWJ0eXBlIikgKwogIHRoZW1lKCNsZWdlbmQucG9zaXRpb249YyguMTEsIC44NCksCiAgICAgICAgbGVnZW5kLm1hcmdpbiA9IG1hcmdpbigwLDAsMCwwKSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCksCiAgICAgICAgbGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KC44LCJsaW5lIikpICMrCiAgI3NjYWxlX3hfY29udGludW91cygjYnJha2VzPSBjKCksCiAgICMgICAgICAgICAgICAgICAgICBsYWJlbCA9IGMoIjAuMSIsIyIxIiwiMTAiLAogICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICIxMDAiLCMiMTAwMCIsCiAgICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgIjEwMDAwMCIpKQpgYGAKCiMjIyMjIHN0ZXB3aXNlIHNlbGVjdGlvbgoKYGBge3IsZXZhbD1GQUxTRSxlY2hvPUZBTFNFfQojIyMgVFVUT1JJQUwKCm1vZGVsLm51bGwgPSBnbG0ocGhlbm8ubnVtIH4gMQogICAgICAgICAgICAsZGF0YT0gbW1vX3hfcm1zLAogICAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbChsaW5rPSJsb2dpdCIpIyxuYS5hY3Rpb24gPSBuYS5vbWl0CiAgICAgICAgICAgICkKCm1vZGVsLmZ1bGwgPSBnbG0ocGhlbm8ubnVtIH4gaWdnICsgaWdnMSArIGlnZzIgKyBpZ2czICsgaWdnNCArIHBhciArIGVkYWQgKyBzZXhvCiAgICAgICAgICAgICxkYXRhPSBtbW9feF9ybXMsCiAgICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKGxpbms9ImxvZ2l0IikjLG5hLmFjdGlvbiA9IG5hLm9taXQKICAgICAgICAgICAgKQoKc3RlcChtb2RlbC5udWxsLAogICAgIHNjb3BlID0gbGlzdCh1cHBlcj1tb2RlbC5mdWxsKSwKICAgICAgICAgICAgIGRpcmVjdGlvbj0iYm90aCIsCiAgICAgICAgICAgICB0ZXN0PSJDaGlzcSIsCiAgICAgICAgICAgICBkYXRhPW1tb194X3JtcykKYGBgCgpgYGB7cixldmFsPUZBTFNFLGVjaG89RkFMU0UsaW5jbHVkZT1GQUxTRX0KbW9kZWwuZmluYWwgPSBnbG0ocGhlbm8ubnVtIH4gaWdnICsgaWdnMSArIGlnZzMgKyBpZ2c0ICsgZWRhZCArIHNleG8KICAgICAgICAgICAgLGRhdGE9IG1tb194X3JtcywKICAgICAgICAgICAgZmFtaWx5ID0gYmlub21pYWwobGluaz0ibG9naXQiKSMsbmEuYWN0aW9uID0gbmEub21pdAogICAgICAgICAgICApCiNzdW1tYXJ5KG1vZGVsLmZpbmFsKQojcmNvbXBhbmlvbjo6bmFnZWxrZXJrZShtb2RlbC5maW5hbCkgI25hZ2Vsa2Vya2UgMC40OTIKI2xtdGVzdDo6bHJ0ZXN0KG1vZGVsLmZpbmFsKSAjMC4wMDAxCiNwbG90KGZpdHRlZChtb2RlbC5maW5hbCkscnN0YW5kYXJkKG1vZGVsLmZpbmFsKSkgI09LCiNzdW1tYXJ5KG1vZGVsLmZpbmFsKSRkZXZpYW5jZSAvIHN1bW1hcnkobW9kZWwuZmluYWwpJGRmLnJlc2lkdWFsICMxLjAxIDwgMS41CmBgYAoKCiMjIyMjIyBzZWxlY3RlZCBtb2RlbAoKYGBge3IsZXZhbD1GQUxTRSxlY2hvPUZBTFNFLGluY2x1ZGU9RkFMU0V9Cm1vZGVsID0gbW9kZWwuZmluYWwKCiNzdW1tYXJ5KG1vZGVsKQoKcGFzdGUoIkFJQz0iLEFJQyhtb2RlbCkpCiNicm9vbTo6YXVnbWVudChtb2RlbCkKI2Jyb29tOjpnbGFuY2UobW9kZWwpICMgVEVTVCBBSUMKI2Jyb29tOjp0aWR5KG1vZGVsKQoKI21vZGVsJGNvZWZmaWNpZW50cwojY29uZmludChtb2RlbCkKZXhwKG1vZGVsJGNvZWZmaWNpZW50cykgICAgICAgICAjIGV4cG9uZW50aWF0ZWQgY29lZmZpY2llbnRzICMgT0REUyBSQVRJTwpleHAoY29uZmludChtb2RlbCkpICAgICAgICAgICAgICMgOTUlIENJIGZvciBleHBvbmVudGlhdGVkIGNvZWZmaWNpZW50cwpgYGAKCmBgYHtyLGZpZy5oZWlnaHQ9Mi4yLGZpZy53aWR0aD0zLjgsZXZhbD1GQUxTRSxlY2hvPUZBTFNFLGluY2x1ZGU9RkFMU0V9CiNjdXQoc2VxKC4wMSwxLGJ5PS4wMDEpLGJyZWFrcyA9IDMpCiNxdWFudGlsZShzZXEoLjAxLC4xLGJ5PS4wMDEpKQojcXVhbnRpbGUoc2VxKC4wMSwuMSxieT0uMDAxKSxwcm9icyA9IGMoMCwwLjMzLDAuNjYsMSkpCkdHYWxseTo6Z2djb2VmKG1vZGVsLGV4cG9uZW50aWF0ZSA9IFQsCiAgICAgICAgICAgICAgIGV4Y2x1ZGVfaW50ZXJjZXB0ID0gVCwKICAgICAgICAgICAgICAgZXJyb3JiYXJfaGVpZ2h0ID0gLjI1LAogICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBlc3RpbWF0ZSwgeSA9IHRlcm0jLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjc2l6ZSA9IHAudmFsdWUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICNjb2xvdXI9cC52YWx1ZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpICsKICBzY2FsZV9zaXplX2NvbnRpbnVvdXModHJhbnMgPSAicmV2ZXJzZSIjLAogICAgICAgICAgICAgICAgICAgICAgICAjbGFiZWxzID0gYXMubnVtZXJpYyhxdWFudGlsZShzZXEoLjAxLC4xLGJ5PS4wMDEpLAogICAgICAgICAgICAgICAgICAgICAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9icyA9IGMoMCwwLjMzLDAuNjYsMSkpCiAgICAgICAgICAgICAgICAgICAgICAgICMgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgIyMsbGltaXRzID0gYyguMSwuMDAxKQogICAgICAgICAgICAgICAgICAgICAgICApICsKICBzY2FsZV9jb2xvdXJfdmlyaWRpc19jKHRyYW5zID0gInJldmVyc2UiIywKICAgICAgICAgICAgICAgICAgICAgICAgI2xhYmVscyA9IGFzLm51bWVyaWMocXVhbnRpbGUoc2VxKC4wMSwuMSxieT0uMDAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYnMgPSBjKDAsMC4zMywwLjY2LDEpKQogICAgICAgICAgICAgICAgICAgICAgICAjICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICMsbGltaXRzID0gYyguMSwuMDAxKQogICAgICAgICAgICAgICAgICAgICAgICApICsKICAjc2NhbGVfeF9sb2cxMCgpICsKICAjY29vcmRfdHJhbnMoeD0ibG9nMTAiKSArCiAgI2Nvb3JkX2NhcnRlc2lhbih4bGltID0gYygtMTAsMTAwKSkgKwogIGxhYnModGl0bGU9IlN1c2NlcHRpYmlsaXR5IHRvIHN5bXB0b21hdGljIG1hbGFyaWEiKSArCiAgI1Byb3RlY3Rpb24gYWdhaW5zdAogICNTdXNjZXB0aWJpbGl0eSB0bwogICNMb3dlciByaXNrIHRvIAogIHhsYWIoIm9kZHMgcmF0aW8gKGxvZyBzY2FsZSkiKSArCiAgeWxhYigiYW50aWJvZHkgc3VidHlwZSIpICsKICB0aGVtZSgjbGVnZW5kLnBvc2l0aW9uPWMoLjExLCAuODQpLAogICAgICAgIGxlZ2VuZC5tYXJnaW4gPSBtYXJnaW4oMCwwLDAsMCksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTApLAogICAgICAgIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCguOCwibGluZSIpKSAjKwogICNzY2FsZV94X2NvbnRpbnVvdXMoI2JyYWtlcz0gYygpLAogICAjICAgICAgICAgICAgICAgICAgbGFiZWwgPSBjKCIwLjEiLCMiMSIsIjEwIiwKICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTAwIiwjIjEwMDAiLAogICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICIxMDAwMDAiKSkKYGBgCgoKIyBSZWZlcmVuY2Vz